@relax.js/core 1.0.0

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.
Files changed (194) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +188 -0
  3. package/dist/DataLoader.d.ts +51 -0
  4. package/dist/DependencyInjection.d.ts +271 -0
  5. package/dist/DependencyInjectionOld.d.ts +35 -0
  6. package/dist/Metadata.d.ts +8 -0
  7. package/dist/SequentialId.d.ts +47 -0
  8. package/dist/_alt/src/MustardEngine.d.ts +30 -0
  9. package/dist/_alt/src/MustardParser.d.ts +63 -0
  10. package/dist/_alt/src/MustardParser2.d.ts +35 -0
  11. package/dist/_alt/src/pipes.d.ts +93 -0
  12. package/dist/_alt/src/template.d.ts +166 -0
  13. package/dist/_alt/src/tools.d.ts +4 -0
  14. package/dist/_alt/tests/pipes.tests.d.ts +1 -0
  15. package/dist/_alt/tests/template.tests.d.ts +1 -0
  16. package/dist/_alt/vitest.config.d.ts +2 -0
  17. package/dist/collections/Index.d.ts +1 -0
  18. package/dist/collections/LinkedList.d.ts +75 -0
  19. package/dist/collections/Pager.d.ts +15 -0
  20. package/dist/collections/index.js +2 -0
  21. package/dist/collections/index.js.map +7 -0
  22. package/dist/collections/index.mjs +2 -0
  23. package/dist/collections/index.mjs.map +7 -0
  24. package/dist/components/Table.d.ts +13 -0
  25. package/dist/components/index.d.ts +4 -0
  26. package/dist/components/index.js +128 -0
  27. package/dist/components/index.js.map +7 -0
  28. package/dist/components/index.mjs +128 -0
  29. package/dist/components/index.mjs.map +7 -0
  30. package/dist/components/lists/Table.d.ts +59 -0
  31. package/dist/components/lists/TreeView.d.ts +67 -0
  32. package/dist/components/lists/index.d.ts +2 -0
  33. package/dist/components/loader.d.ts +60 -0
  34. package/dist/components/menus/MenuItem.d.ts +30 -0
  35. package/dist/components/menus/TopMenu.d.ts +16 -0
  36. package/dist/components/menus/index.d.ts +2 -0
  37. package/dist/components/panels/tabs.d.ts +15 -0
  38. package/dist/di/index.d.ts +1 -0
  39. package/dist/di/index.js +2 -0
  40. package/dist/di/index.js.map +7 -0
  41. package/dist/di/index.mjs +2 -0
  42. package/dist/di/index.mjs.map +7 -0
  43. package/dist/elements/CopyAttributes.d.ts +2 -0
  44. package/dist/elements/dom.d.ts +18 -0
  45. package/dist/elements/index.d.ts +2 -0
  46. package/dist/elements/index.js +2 -0
  47. package/dist/elements/index.js.map +7 -0
  48. package/dist/elements/index.mjs +2 -0
  49. package/dist/elements/index.mjs.map +7 -0
  50. package/dist/errors.d.ts +71 -0
  51. package/dist/forms/FormReader.d.ts +182 -0
  52. package/dist/forms/FormValidator.d.ts +114 -0
  53. package/dist/forms/ValidationRules.d.ts +103 -0
  54. package/dist/forms/index.d.ts +4 -0
  55. package/dist/forms/index.js +2 -0
  56. package/dist/forms/index.js.map +7 -0
  57. package/dist/forms/index.mjs +2 -0
  58. package/dist/forms/index.mjs.map +7 -0
  59. package/dist/forms/setFormData.d.ts +49 -0
  60. package/dist/getParentComponent.d.ts +43 -0
  61. package/dist/html/TableRenderer.d.ts +44 -0
  62. package/dist/html/TreeBinder.d.ts +9 -0
  63. package/dist/html/html.d.ts +55 -0
  64. package/dist/html/index.d.ts +5 -0
  65. package/dist/html/index.js +2 -0
  66. package/dist/html/index.js.map +7 -0
  67. package/dist/html/index.mjs +2 -0
  68. package/dist/html/index.mjs.map +7 -0
  69. package/dist/html/template.d.ts +167 -0
  70. package/dist/http/ServerSentEvents.d.ts +116 -0
  71. package/dist/http/SimpleWebSocket.d.ts +153 -0
  72. package/dist/http/http.d.ts +177 -0
  73. package/dist/http/index.d.ts +3 -0
  74. package/dist/http/index.js +2 -0
  75. package/dist/http/index.js.map +7 -0
  76. package/dist/http/index.mjs +2 -0
  77. package/dist/http/index.mjs.map +7 -0
  78. package/dist/i18n/i18n.d.ts +105 -0
  79. package/dist/i18n/icu.d.ts +64 -0
  80. package/dist/i18n/index.d.ts +2 -0
  81. package/dist/i18n/index.js +2 -0
  82. package/dist/i18n/index.js.map +7 -0
  83. package/dist/i18n/index.mjs +2 -0
  84. package/dist/i18n/index.mjs.map +7 -0
  85. package/dist/index.d.ts +16 -0
  86. package/dist/index.js +5 -0
  87. package/dist/index.js.map +7 -0
  88. package/dist/index.mjs +5 -0
  89. package/dist/index.mjs.map +7 -0
  90. package/dist/lib/DataLoader.d.ts +51 -0
  91. package/dist/lib/DependencyInjection.d.ts +271 -0
  92. package/dist/lib/InvokeParent.d.ts +10 -0
  93. package/dist/lib/Pipes.d.ts +236 -0
  94. package/dist/lib/SequentialId.d.ts +47 -0
  95. package/dist/lib/collections/Index.d.ts +1 -0
  96. package/dist/lib/collections/LinkedList.d.ts +75 -0
  97. package/dist/lib/collections/Pager.d.ts +15 -0
  98. package/dist/lib/collections/TableRenderer.d.ts +44 -0
  99. package/dist/lib/di/index.d.ts +1 -0
  100. package/dist/lib/elements/CopyAttributes.d.ts +2 -0
  101. package/dist/lib/elements/dom.d.ts +18 -0
  102. package/dist/lib/elements/index.d.ts +2 -0
  103. package/dist/lib/errors.d.ts +71 -0
  104. package/dist/lib/forms/FormReader.d.ts +182 -0
  105. package/dist/lib/forms/FormValidator.d.ts +114 -0
  106. package/dist/lib/forms/ValidationRules.d.ts +103 -0
  107. package/dist/lib/forms/index.d.ts +4 -0
  108. package/dist/lib/forms/setFormData.d.ts +49 -0
  109. package/dist/lib/getParentComponent.d.ts +43 -0
  110. package/dist/lib/html/TableRenderer.d.ts +44 -0
  111. package/dist/lib/html/TreeBinder.d.ts +9 -0
  112. package/dist/lib/html/html.d.ts +55 -0
  113. package/dist/lib/html/html2.d.ts +55 -0
  114. package/dist/lib/html/index.d.ts +5 -0
  115. package/dist/lib/html/m.d.ts +167 -0
  116. package/dist/lib/html/m2.d.ts +8 -0
  117. package/dist/lib/html/m3.d.ts +0 -0
  118. package/dist/lib/html/template.d.ts +167 -0
  119. package/dist/lib/http/HttpClient.d.ts +153 -0
  120. package/dist/lib/http/ServerSentEvents.d.ts +116 -0
  121. package/dist/lib/http/SimpleWebSocket.d.ts +153 -0
  122. package/dist/lib/http/http.d.ts +177 -0
  123. package/dist/lib/http/index.d.ts +3 -0
  124. package/dist/lib/i18n/i18n.d.ts +105 -0
  125. package/dist/lib/i18n/icu.d.ts +64 -0
  126. package/dist/lib/i18n/index.d.ts +2 -0
  127. package/dist/lib/index.d.ts +16 -0
  128. package/dist/lib/routing/NavigateRouteEvent.d.ts +52 -0
  129. package/dist/lib/routing/RouteLink.d.ts +7 -0
  130. package/dist/lib/routing/Routing.d.ts +270 -0
  131. package/dist/lib/routing/RoutingTarget.d.ts +22 -0
  132. package/dist/lib/routing/index.d.ts +7 -0
  133. package/dist/lib/routing/navigation.d.ts +70 -0
  134. package/dist/lib/routing/routeMatching.d.ts +21 -0
  135. package/dist/lib/routing/routeTargetRegistry.d.ts +23 -0
  136. package/dist/lib/routing/types.d.ts +130 -0
  137. package/dist/lib/templates/NodeTemplate.d.ts +38 -0
  138. package/dist/lib/templates/accessorParser.d.ts +87 -0
  139. package/dist/lib/templates/parseTemplate.d.ts +6 -0
  140. package/dist/lib/templates/tokenizer.d.ts +76 -0
  141. package/dist/lib/tools.d.ts +30 -0
  142. package/dist/lib/utils/index.d.ts +4 -0
  143. package/dist/pipes.d.ts +236 -0
  144. package/dist/routing/NavigateRouteEvent.d.ts +52 -0
  145. package/dist/routing/RouteLink.d.ts +7 -0
  146. package/dist/routing/RoutingTarget.d.ts +22 -0
  147. package/dist/routing/index.d.ts +7 -0
  148. package/dist/routing/index.js +5 -0
  149. package/dist/routing/index.js.map +7 -0
  150. package/dist/routing/index.mjs +5 -0
  151. package/dist/routing/index.mjs.map +7 -0
  152. package/dist/routing/navigation.d.ts +70 -0
  153. package/dist/routing/routeMatching.d.ts +21 -0
  154. package/dist/routing/routeTargetRegistry.d.ts +23 -0
  155. package/dist/routing/types.d.ts +130 -0
  156. package/dist/templates/NodeTemplate.d.ts +38 -0
  157. package/dist/templates/accessorParser.d.ts +87 -0
  158. package/dist/templates/parseTemplate.d.ts +6 -0
  159. package/dist/templates/tokenizer.d.ts +76 -0
  160. package/dist/tools.d.ts +30 -0
  161. package/dist/utils/index.d.ts +4 -0
  162. package/dist/utils/index.js +2 -0
  163. package/dist/utils/index.js.map +7 -0
  164. package/dist/utils/index.mjs +2 -0
  165. package/dist/utils/index.mjs.map +7 -0
  166. package/docs/Architecture.md +333 -0
  167. package/docs/DependencyInjection.md +237 -0
  168. package/docs/Errors.md +87 -0
  169. package/docs/GettingStarted.md +231 -0
  170. package/docs/Pipes.md +211 -0
  171. package/docs/Translations.md +312 -0
  172. package/docs/WhyRelaxjs.md +336 -0
  173. package/docs/elements/dom.md +102 -0
  174. package/docs/forms/creating-form-components.md +924 -0
  175. package/docs/forms/form-api.md +94 -0
  176. package/docs/forms/forms.md +99 -0
  177. package/docs/forms/patterns.md +311 -0
  178. package/docs/forms/reading-writing.md +365 -0
  179. package/docs/forms/validation.md +351 -0
  180. package/docs/html/TableRenderer.md +292 -0
  181. package/docs/html/html.md +175 -0
  182. package/docs/html/index.md +54 -0
  183. package/docs/html/template.md +422 -0
  184. package/docs/http/HttpClient.md +459 -0
  185. package/docs/http/ServerSentEvents.md +184 -0
  186. package/docs/http/index.md +109 -0
  187. package/docs/i18n/i18n.md +309 -0
  188. package/docs/i18n/intl-standard.md +178 -0
  189. package/docs/routing/RouteLink.md +98 -0
  190. package/docs/routing/Routing.md +332 -0
  191. package/docs/routing/RoutingTarget.md +136 -0
  192. package/docs/routing/layouts.md +207 -0
  193. package/docs/utilities.md +143 -0
  194. package/package.json +93 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/i18n/locales/en/r-common.json", "../../src/i18n/locales/en/r-pipes.json", "../../src/i18n/locales/en/r-validation.json", "../../src/i18n/locales/sv/r-common.json", "../../src/i18n/locales/sv/r-pipes.json", "../../src/i18n/locales/sv/r-validation.json", "../../src/forms/index.ts", "../../src/i18n/icu.ts", "../../src/i18n/i18n.ts", "../../src/forms/FormReader.ts", "../../src/forms/FormValidator.ts", "../../src/forms/setFormData.ts", "../../src/forms/ValidationRules.ts"],
4
+ "sourcesContent": ["{\r\n \"greeting\": \"Hello, {name}!\",\r\n \"items\": \"{count, plural, one {# item} other {# items}}\"\r\n}\r\n", "{\r\n \"today\": \"today\",\r\n \"yesterday\": \"yesterday\",\r\n \"daysAgo\": \"{count, plural, one {# day ago} other {# days ago}}\",\r\n \"pieces\": \"{count, plural, =0 {none} one {one} other {# pcs}}\"\r\n}\r\n", "{\r\n \"required\": \"This field is required.\",\r\n \"range\": \"Number must be between {min} and {max}, was {actual}.\",\r\n \"digits\": \"Please enter only digits.\"\r\n}\r\n", "{\r\n \"greeting\": \"Hej, {name}!\",\r\n \"items\": \"{count, plural, one {# sak} other {# saker}}\"\r\n}\r\n", "{\r\n \"today\": \"idag\",\r\n \"yesterday\": \"ig\u00E5r\",\r\n \"daysAgo\": \"{count, plural, one {# dag sedan} other {# dagar sedan}}\",\r\n \"pieces\": \"{count, plural, =0 {inga} one {en} other {# st}}\"\r\n}\r\n", "{\r\n \"required\": \"Detta f\u00E4lt \u00E4r obligatoriskt.\",\r\n \"range\": \"Talet m\u00E5ste vara mellan {min} och {max}, var {actual}.\",\r\n \"digits\": \"Ange endast siffror.\"\r\n}\r\n", "export {\r\n FormReaderOptions,\r\n ConverterFunc,\r\n DataType,\r\n InputType,\r\n mapFormToClass,\r\n getDataConverter,\r\n readData,\r\n BooleanConverter,\r\n NumberConverter,\r\n DateConverter,\r\n createConverterFromDataType,\r\n createConverterFromInputType\r\n} from './FormReader';\r\n\r\nexport {\r\n ValidatorOptions,\r\n FormValidator\r\n} from './FormValidator';\r\n\r\nexport { setFormData } from './setFormData';\r\n\r\nexport {\r\n ValidationContext,\r\n RegisterValidator,\r\n getValidator,\r\n RequiredValidation,\r\n RangeValidation,\r\n DigitsValidation\r\n} from './ValidationRules';\r\n", "/**\r\n * @module icu\r\n * ICU message format support for internationalization.\r\n * Provides pluralization, select, and value interpolation.\r\n *\r\n * @example\r\n * // Simple interpolation\r\n * formatICU('Hello, {name}!', { name: 'World' });\r\n * // Returns: 'Hello, World!'\r\n *\r\n * @example\r\n * // Pluralization\r\n * formatICU('{count, plural, one {# item} other {# items}}', { count: 5 });\r\n * // Returns: '5 items'\r\n *\r\n * @example\r\n * // Select\r\n * formatICU('{gender, select, male {He} female {She} other {They}}', { gender: 'female' });\r\n * // Returns: 'She'\r\n */\r\n\r\nconst pluralRulesCache = new Map<string, Intl.PluralRules>();\r\n\r\n/**\r\n * Function type for message formatters.\r\n * Implement this to provide custom message formatting.\r\n */\r\nexport type MessageFormatter = (\r\n message: string,\r\n values?: Record<string, any>,\r\n locale?: string\r\n) => string;\r\n\r\n\r\nfunction getPluralRule(locale: string): Intl.PluralRules {\r\n if (!pluralRulesCache.has(locale)) {\r\n pluralRulesCache.set(locale, new Intl.PluralRules(locale));\r\n }\r\n return pluralRulesCache.get(locale)!;\r\n}\r\n\r\nfunction escapeRegex(s: string): string {\r\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n}\r\n\r\n/**\r\n * Default ICU message formatter implementation.\r\n * Supports simple interpolation, pluralization with exact matches, and select.\r\n *\r\n * @param message - ICU format message string\r\n * @param values - Values to interpolate\r\n * @param locale - Locale for plural rules (default: 'en')\r\n * @returns Formatted message string\r\n *\r\n * @example\r\n * defaultFormatICU('{n, plural, =0 {none} one {# item} other {# items}}', { n: 0 }, 'en');\r\n * // Returns: 'none'\r\n *\r\n * @example\r\n * defaultFormatICU('{role, select, admin {Full access} other {Limited access}}', { role: 'admin' });\r\n * // Returns: 'Full access'\r\n */\r\nexport function defaultFormatICU(\r\n message: string,\r\n values: Record<string, any>,\r\n locale: string = 'en'\r\n): string {\r\n return message.replace(\r\n /\\{(\\w+)(?:, (plural|select),((?:[^{}]*\\{[^{}]*\\})+))?\\}/g,\r\n (_, key, type, categoriesPart) => {\r\n const value = values[key];\r\n\r\n if (type === 'plural') {\r\n const exact = new RegExp(\r\n `=${escapeRegex(String(value))}\\\\s*\\\\{([^{}]*)\\\\}`\r\n ).exec(categoriesPart);\r\n if (exact) {\r\n return exact[1]\r\n .replace(`{${key}}`, String(value))\r\n .replace('#', String(value));\r\n }\r\n\r\n const rules = getPluralRule(locale);\r\n const category = rules.select(value);\r\n const match =\r\n new RegExp(`${category}\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart) ||\r\n new RegExp(`other\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart);\r\n if (match) {\r\n return match[1]\r\n .replace(`{${key}}`, String(value))\r\n .replace('#', String(value));\r\n }\r\n return String(value);\r\n }\r\n\r\n if (type === 'select') {\r\n const escaped = escapeRegex(String(value));\r\n const match =\r\n new RegExp(`\\\\b${escaped}\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart) ||\r\n new RegExp(`\\\\bother\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart);\r\n return match ? match[1] : String(value);\r\n }\r\n\r\n return value !== undefined ? String(value) : `{${key}}`;\r\n },\r\n );\r\n}\r\n\r\n/**\r\n * The active message formatter. Defaults to `defaultFormatICU`.\r\n * Can be replaced with `setMessageFormatter` for custom formatting.\r\n */\r\nexport let formatICU: MessageFormatter = defaultFormatICU;\r\n\r\n/**\r\n * Replaces the default message formatter with a custom implementation.\r\n * Use this to integrate with external i18n libraries like FormatJS.\r\n *\r\n * @param formatter - The custom formatter function\r\n *\r\n * @example\r\n * // Use FormatJS IntlMessageFormat\r\n * import { IntlMessageFormat } from 'intl-messageformat';\r\n *\r\n * setMessageFormatter((message, values, locale) => {\r\n * const fmt = new IntlMessageFormat(message, locale);\r\n * return fmt.format(values);\r\n * });\r\n */\r\nexport function setMessageFormatter(formatter: MessageFormatter) {\r\n formatICU = formatter;\r\n}", "/**\r\n * @module i18n\r\n * Internationalization support with namespace-based translations.\r\n * Uses ICU message format for pluralization, select, and formatting.\r\n *\r\n * @example\r\n * // Initialize locale\r\n * await setLocale('sv');\r\n *\r\n * // Use translations\r\n * const greeting = t('r-common:greeting', { name: 'John' });\r\n * const items = t('shop:items', { count: 5 });\r\n */\r\n\r\nimport { formatICU } from './icu';\r\n\r\ntype Locale = string;\r\ntype Namespace = string;\r\ntype TranslationMap = Record<string, string>;\r\ntype Translations = Record<Namespace, TranslationMap>;\r\n\r\nexport type MissingTranslationHandler = (\r\n key: string,\r\n namespace: string,\r\n locale: string,\r\n) => void;\r\n\r\n/**\r\n * Dispatched on `document` after `setLocale()` completes.\r\n * The `locale` property contains the new normalized locale code.\r\n *\r\n * @example\r\n * document.addEventListener('localechange', (e) => {\r\n * console.log(`Locale changed to ${e.locale}`);\r\n * this.render();\r\n * });\r\n */\r\nexport class LocaleChangeEvent extends Event {\r\n readonly locale: string;\r\n constructor(locale: string) {\r\n super('localechange', { bubbles: false });\r\n this.locale = locale;\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface DocumentEventMap {\r\n localechange: LocaleChangeEvent;\r\n }\r\n}\r\n\r\nconst fallbackLocale: Locale = 'en';\r\nlet currentLocale: Locale = fallbackLocale;\r\nconst loadedNamespaces = new Set<Namespace>();\r\nconst translations: Translations = {};\r\nlet missingHandler: MissingTranslationHandler | null = null;\r\n\r\nfunction normalizeLocale(locale: string): string {\r\n return locale.toLowerCase().split('-')[0];\r\n}\r\n\r\n/**\r\n * Sets the current locale and loads the common namespace.\r\n * Clears previously loaded translations and dispatches a `localechange` event.\r\n *\r\n * @param locale - The locale code (e.g., 'en', 'sv', 'en-US')\r\n *\r\n * @example\r\n * await setLocale('sv');\r\n */\r\nexport async function setLocale(locale: string): Promise<void> {\r\n const normalized = normalizeLocale(locale);\r\n currentLocale = normalized;\r\n loadedNamespaces.clear();\r\n Object.keys(translations).forEach(ns => delete translations[ns]);\r\n await loadNamespace('r-common');\r\n if (typeof document !== 'undefined') {\r\n document.dispatchEvent(new LocaleChangeEvent(normalized));\r\n }\r\n}\r\n\r\n/**\r\n * Loads a translation namespace on demand.\r\n * Falls back to the default locale if translations are not found.\r\n *\r\n * @param namespace - The namespace to load (e.g., 'shop', 'errors')\r\n *\r\n * @example\r\n * await loadNamespace('shop');\r\n * const price = t('shop:priceLabel');\r\n */\r\nexport async function loadNamespace(namespace: Namespace): Promise<void> {\r\n if (loadedNamespaces.has(namespace)) return;\r\n\r\n try {\r\n const module = await import(`./locales/${currentLocale}/${namespace}.json`);\r\n translations[namespace] = module.default;\r\n loadedNamespaces.add(namespace);\r\n } catch (err) {\r\n if (currentLocale !== fallbackLocale) {\r\n const fallback = await import(`./locales/${fallbackLocale}/${namespace}.json`);\r\n translations[namespace] = fallback.default;\r\n loadedNamespaces.add(namespace);\r\n } else {\r\n console.warn(`i18n: Failed to load namespace '${namespace}' for locale '${currentLocale}'`);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Loads multiple translation namespaces in parallel.\r\n *\r\n * @param namespaces - Array of namespace names to load\r\n *\r\n * @example\r\n * await loadNamespaces(['r-pipes', 'r-validation']);\r\n */\r\nexport async function loadNamespaces(namespaces: Namespace[]): Promise<void> {\r\n await Promise.all(namespaces.map(ns => loadNamespace(ns)));\r\n}\r\n\r\n/**\r\n * Translates a key with optional value interpolation.\r\n * Supports ICU message format for pluralization and select.\r\n *\r\n * @param fullKey - Translation key in format 'namespace:key' or just 'key' (uses 'r-common')\r\n * @param values - Values to interpolate into the message\r\n * @returns The translated string, or the key if not found\r\n *\r\n * @example\r\n * // Simple translation\r\n * t('greeting'); // Uses r-common:greeting\r\n *\r\n * // With namespace\r\n * t('errors:notFound');\r\n *\r\n * // With interpolation\r\n * t('welcome', { name: 'John' }); // \"Welcome, John!\"\r\n *\r\n * // With pluralization (ICU format)\r\n * t('items', { count: 5 }); // \"5 items\" or \"5 f\u00F6rem\u00E5l\"\r\n */\r\nexport function t(fullKey: string, values?: Record<string, any>): string {\r\n const [namespace, key] = fullKey.includes(':')\r\n ? fullKey.split(':')\r\n : ['r-common', fullKey];\r\n const message = translations[namespace]?.[key];\r\n if (!message) {\r\n if (missingHandler) missingHandler(key, namespace, currentLocale);\r\n return fullKey;\r\n }\r\n try {\r\n return formatICU(message, values, currentLocale) as string;\r\n } catch {\r\n return fullKey;\r\n }\r\n}\r\n\r\n/**\r\n * Returns the current locale code.\r\n *\r\n * @returns The normalized locale code (e.g., 'en', 'sv')\r\n */\r\nexport function getCurrentLocale(): string {\r\n return currentLocale;\r\n}\r\n\r\n/**\r\n * Registers a handler called when `t()` encounters a missing translation key.\r\n * Pass `null` to remove the handler.\r\n *\r\n * @param handler - Callback receiving the key, namespace, and locale\r\n *\r\n * @example\r\n * onMissingTranslation((key, ns, locale) => {\r\n * console.warn(`Missing: ${ns}:${key} [${locale}]`);\r\n * });\r\n */\r\nexport function onMissingTranslation(handler: MissingTranslationHandler | null): void {\r\n missingHandler = handler;\r\n}\r\n", "/**\r\n * @module FormReader\r\n * Utilities for reading form data into typed objects.\r\n * Handles type conversion based on input types and data-type attributes.\r\n *\r\n * @example\r\n * // Basic form reading\r\n * const form = document.querySelector('form');\r\n * const data = readData(form);\r\n *\r\n * // Type-safe mapping to a class instance\r\n * const user = mapFormToClass(form, new UserDTO());\r\n */\r\n\r\nimport { getCurrentLocale } from '../i18n/i18n';\r\n\r\n/**\r\n * Maps form field values to a class instance's properties.\r\n * Automatically converts values based on input types (checkbox, number, date).\r\n *\r\n * Form field names must match property names on the target instance.\r\n *\r\n * @template T - The type of the class instance\r\n * @param form - The HTML form element to read from\r\n * @param instance - The class instance to populate\r\n * @param options - Configuration options\r\n * @param options.throwOnMissingProperty - Throw if form field has no matching property\r\n * @param options.throwOnMissingField - Throw if class property has no matching form field\r\n * @returns The populated instance\r\n *\r\n * @example\r\n * class UserDTO {\r\n * name: string = '';\r\n * email: string = '';\r\n * age: number = 0;\r\n * newsletter: boolean = false;\r\n * }\r\n *\r\n * const form = document.querySelector('form');\r\n * const user = mapFormToClass(form, new UserDTO());\r\n * console.log(user.name, user.age, user.newsletter);\r\n *\r\n * @example\r\n * // With validation\r\n * const user = mapFormToClass(form, new UserDTO(), {\r\n * throwOnMissingProperty: true, // Catch typos in form field names\r\n * throwOnMissingField: true // Ensure all DTO fields are in form\r\n * });\r\n */\r\nexport function mapFormToClass<T extends object>(\r\n form: HTMLFormElement,\r\n instance: T,\r\n options: {\r\n throwOnMissingProperty?: boolean;\r\n throwOnMissingField?: boolean;\r\n } = {}\r\n): T {\r\n const formElements = form.querySelectorAll('input, select, textarea');\r\n\r\n formElements.forEach((element) => {\r\n if (!element.hasAttribute('name')) return;\r\n if (booleanAttr(element, 'disabled')) return;\r\n\r\n const propertyName = element.getAttribute('name')!;\r\n\r\n if (!(propertyName in instance)) {\r\n if (options.throwOnMissingProperty) {\r\n throw new Error(\r\n `Form field \"${propertyName}\" has no matching property in class instance`\r\n );\r\n }\r\n return;\r\n }\r\n\r\n const value = readElementValue(element);\r\n if (value === SKIP) return;\r\n\r\n (instance as Record<string, unknown>)[propertyName] = value;\r\n });\r\n\r\n if (options.throwOnMissingField) {\r\n const formFieldNames = new Set<string>();\r\n formElements.forEach((element) => {\r\n if (element.hasAttribute('name')) {\r\n formFieldNames.add(element.getAttribute('name')!);\r\n }\r\n });\r\n\r\n for (const prop in instance) {\r\n if (\r\n typeof instance[prop] !== 'function' &&\r\n Object.prototype.hasOwnProperty.call(instance, prop) &&\r\n !formFieldNames.has(prop)\r\n ) {\r\n throw new Error(\r\n `Class property \"${prop}\" has no matching form field`\r\n );\r\n }\r\n }\r\n }\r\n\r\n return instance;\r\n}\r\n\r\n/**\r\n * Configuration options for form reading operations.\r\n */\r\nexport interface FormReaderOptions {\r\n /** Prefix to strip from field names when mapping to properties */\r\n prefix?: string;\r\n /** If true, checkboxes return their value instead of true/false */\r\n disableBinaryCheckbox?: boolean;\r\n /** If true, radio buttons return their value instead of true/false */\r\n disableBinaryRadioButton?: boolean;\r\n}\r\n\r\n/**\r\n * Gets the appropriate type converter function for a form element.\r\n * Uses the `data-type` attribute if present, otherwise infers from input type.\r\n *\r\n * @param element - The form element to get a converter for\r\n * @returns A function that converts string values to the appropriate type\r\n *\r\n * @example\r\n * // With data-type attribute\r\n * <input name=\"age\" data-type=\"number\" />\r\n * const converter = getDataConverter(input);\r\n * converter('42'); // Returns: 42 (number)\r\n *\r\n * @example\r\n * // Inferred from input type\r\n * <input type=\"checkbox\" name=\"active\" />\r\n * const converter = getDataConverter(checkbox);\r\n * converter('true'); // Returns: true (boolean)\r\n */\r\nexport function getDataConverter(element: HTMLElement): ConverterFunc {\r\n const dataType = element.getAttribute('data-type') as DataType | null;\r\n if (dataType) {\r\n return createConverterFromDataType(dataType);\r\n }\r\n\r\n if (element instanceof HTMLInputElement) {\r\n return createConverterFromInputType(element.type as InputType);\r\n }\r\n\r\n // Handle custom form-associated elements with checked property (boolean values)\r\n if ('checked' in element && typeof (element as any).checked === 'boolean') {\r\n return BooleanConverter as ConverterFunc;\r\n }\r\n\r\n return (str) => str;\r\n}\r\n\r\n\r\n/**\r\n * Reads all form data into a plain object with automatic type conversion.\r\n * Handles multiple values (e.g., multi-select) and custom form-associated elements.\r\n *\r\n * Type conversion is based on:\r\n * 1. `data-type` attribute if present (number, boolean, string, Date)\r\n * 2. Input type (checkbox, number, date, etc.)\r\n * 3. Falls back to string\r\n *\r\n * @param form - The HTML form element to read\r\n * @returns Object with property names matching field names\r\n *\r\n * @example\r\n * // HTML form\r\n * <form>\r\n * <input name=\"username\" value=\"john\" />\r\n * <input name=\"age\" type=\"number\" value=\"25\" />\r\n * <input name=\"active\" type=\"checkbox\" checked />\r\n * <select name=\"colors\" multiple>\r\n * <option value=\"red\" selected>Red</option>\r\n * <option value=\"blue\" selected>Blue</option>\r\n * </select>\r\n * </form>\r\n *\r\n * // Reading the form\r\n * const data = readData(form);\r\n * // Returns: { username: 'john', age: 25, active: true, colors: ['red', 'blue'] }\r\n *\r\n * @example\r\n * // With custom form elements\r\n * <form>\r\n * <r-input name=\"email\" value=\"test@example.com\" />\r\n * <r-checkbox name=\"terms\" checked />\r\n * </form>\r\n * const data = readData(form);\r\n 1*/\r\nexport function readData<T = Record<string, unknown>>(form: HTMLFormElement): T{\r\n const data: Record<string, unknown> = {};\r\n const formData = new FormData(form);\r\n const seen = new Set<string>();\r\n\r\n formData.forEach((_, name) => {\r\n if (seen.has(name)) return;\r\n seen.add(name);\r\n\r\n const values = formData.getAll(name);\r\n const element = form.elements.namedItem(name);\r\n const converter = element ? getDataConverter(element as HTMLElement) : (v: string) => v;\r\n\r\n if (values.length === 1) {\r\n const v = values[0];\r\n data[name] = typeof v === 'string' ? converter(v) : v;\r\n } else {\r\n data[name] = values.map(v => typeof v === 'string' ? converter(v) : v);\r\n }\r\n });\r\n\r\n for (let i = 0; i < form.elements.length; i++) {\r\n const el = form.elements[i] as HTMLInputElement;\r\n if (el.type === 'checkbox' && el.name && !seen.has(el.name)) {\r\n seen.add(el.name);\r\n data[el.name] = false;\r\n }\r\n }\r\n\r\n return data as T;\r\n}\r\n\r\n/**\r\n * Function type for converting string form values to typed values.\r\n */\r\nexport type ConverterFunc = (value: string) => unknown;\r\n\r\n/**\r\n * Supported data-type attribute values for explicit type conversion.\r\n */\r\nexport type DataType = 'number' | 'boolean' | 'string' | 'Date';\r\n\r\n/**\r\n * Supported HTML input types for automatic type inference.\r\n */\r\nexport type InputType =\r\n | 'tel'\r\n | 'text'\r\n | 'checkbox'\r\n | 'radio'\r\n | 'number'\r\n | 'color'\r\n | 'date'\r\n | 'datetime-local'\r\n | 'month'\r\n | 'week'\r\n | 'time';\r\n\r\n/**\r\n * Converts string values to booleans.\r\n * Handles 'true'/'false' strings and numeric values (>0 is true).\r\n *\r\n * @param value - String value to convert\r\n * @returns Boolean value or undefined if empty\r\n * @throws Error if value cannot be interpreted as boolean\r\n */\r\nexport function BooleanConverter(value?: string): boolean | undefined {\r\n if (!value || value == '') {\r\n return undefined;\r\n }\r\n\r\n const lower = value.toLowerCase();\r\n\r\n if (lower === 'true' || lower === 'on' || Number(value) > 0) {\r\n return true;\r\n }\r\n\r\n if (lower === 'false' || lower === 'off' || Number(value) <= 0) {\r\n return false;\r\n }\r\n\r\n throw new Error(\"Could not convert value '\" + value + \"' to boolean.\");\r\n}\r\n\r\n/**\r\n * Converts string values to numbers.\r\n *\r\n * @param value - String value to convert\r\n * @returns Number value or undefined if empty\r\n * @throws Error if value is not a valid number\r\n */\r\nexport function NumberConverter(value?: string): number | undefined {\r\n if (!value || value == '') {\r\n return undefined;\r\n }\r\n const nr = Number(value);\r\n if (!isNaN(nr)) {\r\n return nr;\r\n }\r\n throw new Error(\"Could not convert value '\" + value + \"' to number.\");\r\n}\r\n\r\n/**\r\n * Detects the order of day/month/year parts for a given locale\r\n * using `Intl.DateTimeFormat.formatToParts`.\r\n *\r\n * @example\r\n * getLocaleDateOrder('en-US') // ['month', 'day', 'year']\r\n * getLocaleDateOrder('sv') // ['year', 'month', 'day']\r\n * getLocaleDateOrder('de') // ['day', 'month', 'year']\r\n */\r\nfunction getLocaleDateOrder(locale: string): ('day' | 'month' | 'year')[] {\r\n const parts = new Intl.DateTimeFormat(locale).formatToParts(new Date(2024, 0, 15));\r\n return parts\r\n .filter((p): p is Intl.DateTimeFormatPart & { type: 'day' | 'month' | 'year' } =>\r\n p.type === 'day' || p.type === 'month' || p.type === 'year')\r\n .map(p => p.type);\r\n}\r\n\r\n/**\r\n * Converts string values to Date objects.\r\n * Supports both ISO format (`2024-01-15`) and locale-specific formats\r\n * (`01/15/2024` for en-US, `15.01.2024` for de, etc.) based on the\r\n * current i18n locale.\r\n *\r\n * @param value - Date string in ISO or locale format\r\n * @returns Date object\r\n * @throws Error if value is not a valid date\r\n *\r\n * @example\r\n * // ISO format (from <input type=\"date\">)\r\n * DateConverter('2024-01-15') // Date(2024, 0, 15)\r\n *\r\n * // Locale format (from <input type=\"text\" data-type=\"Date\">)\r\n * // with locale set to 'sv': 2024-01-15\r\n * // with locale set to 'en-US': 01/15/2024\r\n * // with locale set to 'de': 15.01.2024\r\n */\r\nexport function DateConverter(value: string): Date | undefined {\r\n if (!value || value === '') return undefined;\r\n\r\n if (/^\\d{4}-\\d{2}-\\d{2}(T|$)/.test(value)) {\r\n const date = new Date(value);\r\n if (!isNaN(date.getTime())) return date;\r\n }\r\n\r\n const numericParts = value.split(/[\\/.\\-\\s]/);\r\n if (numericParts.length >= 3 && numericParts.every(p => /^\\d+$/.test(p))) {\r\n const locale = getCurrentLocale();\r\n const order = getLocaleDateOrder(locale);\r\n const mapped: Record<string, number> = {};\r\n order.forEach((type, i) => {\r\n mapped[type] = parseInt(numericParts[i], 10);\r\n });\r\n\r\n if (mapped.year !== undefined && mapped.month !== undefined && mapped.day !== undefined) {\r\n if (mapped.year < 100) mapped.year += 2000;\r\n const date = new Date(mapped.year, mapped.month - 1, mapped.day);\r\n if (!isNaN(date.getTime())) return date;\r\n }\r\n }\r\n\r\n const date = new Date(value);\r\n if (isNaN(date.getTime())) {\r\n throw new Error('Invalid date format');\r\n }\r\n return date;\r\n}\r\n\r\n/**\r\n * Creates a converter function based on the data-type attribute value.\r\n *\r\n * @param dataType - The data-type attribute value\r\n * @returns Appropriate converter function for the type\r\n */\r\nexport function createConverterFromDataType(dataType: DataType): ConverterFunc {\r\n switch (dataType) {\r\n case 'boolean':\r\n return BooleanConverter as ConverterFunc;\r\n case 'number':\r\n return NumberConverter as ConverterFunc;\r\n case 'Date':\r\n return DateConverter;\r\n case 'string':\r\n return (value) => (!value || value == '' ? undefined : value);\r\n default:\r\n throw new Error(`Unknown data-type \"${dataType}\".`);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a converter function based on HTML input type.\r\n * Handles special types like checkbox, date, time, week, and month.\r\n *\r\n * @param inputType - The HTML input type attribute value\r\n * @returns Appropriate converter function for the type\r\n */\r\nexport function createConverterFromInputType(inputType: InputType): ConverterFunc {\r\n switch (inputType) {\r\n case 'checkbox':\r\n return BooleanConverter as ConverterFunc;\r\n\r\n case 'number':\r\n return NumberConverter as ConverterFunc;\r\n\r\n case 'date':\r\n case 'datetime-local':\r\n return DateConverter;\r\n\r\n case 'month':\r\n return (value) => {\r\n const [year, month] = value.split('-').map(Number);\r\n return new Date(year, month - 1);\r\n };\r\n\r\n case 'week':\r\n return (value) => {\r\n const [year, week] = value.split('-W').map(Number);\r\n return { year, week };\r\n };\r\n\r\n case 'time':\r\n return (value) => {\r\n const [hours, minutes, seconds = 0] = value.split(':').map(Number);\r\n return { hours, minutes, seconds };\r\n };\r\n\r\n default:\r\n return (value) => (!value || value == '' ? undefined : value);\r\n }\r\n}\r\n\r\nfunction booleanAttr(element: Element, name: string): boolean {\r\n const el = element as Record<string, any>;\r\n if (name in el && typeof el[name] === 'boolean') return el[name];\r\n const attr = element.getAttribute(name);\r\n if (attr === null) return false;\r\n if (attr === '' || attr.toLowerCase() === 'true' || attr.toLowerCase() === name) return true;\r\n return false;\r\n}\r\n\r\nconst SKIP = Symbol('skip');\r\n\r\nfunction readElementValue(element: Element): unknown {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox') {\r\n return booleanAttr(element, 'checked');\r\n }\r\n\r\n if (type === 'radio') {\r\n if (!booleanAttr(element, 'checked')) return SKIP;\r\n return el.value;\r\n }\r\n\r\n if (type === 'number') {\r\n return el.value ? Number(el.value) : null;\r\n }\r\n\r\n if (type === 'date') {\r\n return el.value ? new Date(el.value) : null;\r\n }\r\n\r\n if ('selectedOptions' in el && booleanAttr(element, 'multiple')) {\r\n return Array.from(el.selectedOptions as NodeListOf<HTMLOptionElement>)\r\n .map((o: HTMLOptionElement) => o.value);\r\n }\r\n\r\n if ('value' in el) {\r\n return el.value;\r\n }\r\n\r\n return undefined;\r\n}", "/**\r\n * @module FormValidator\r\n * Form validation with support for native HTML5 validation and error summaries.\r\n * Provides automatic validation on submit with customizable behavior.\r\n *\r\n * @example\r\n * // Basic usage with submit callback\r\n * const form = document.querySelector('form');\r\n * const validator = new FormValidator(form, {\r\n * submitCallback: () => saveData()\r\n * });\r\n *\r\n * @example\r\n * // With auto-validation on input\r\n * const validator = new FormValidator(form, {\r\n * autoValidate: true,\r\n * useSummary: true\r\n * });\r\n */\r\n\r\n/**\r\n * Gets the human-readable field name from its associated label.\r\n */\r\nfunction getFieldName(element: HTMLElement): string | null {\r\n const id = element.getAttribute('id');\r\n if (id) {\r\n const form = element.closest('form');\r\n if (form) {\r\n const label = form.querySelector(`label[for=\"${id}\"]`) as HTMLLabelElement | null;\r\n if (label) {\r\n return label.textContent?.trim() || null;\r\n }\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Configuration options for FormValidator.\r\n */\r\nexport interface ValidatorOptions {\r\n /** Validate on every input event, not just submit */\r\n autoValidate?: boolean;\r\n /** Show errors in a summary element instead of browser tooltips */\r\n useSummary?: boolean;\r\n /** Custom validation function called before native validation */\r\n customChecks?: (form: HTMLFormElement) => void;\r\n /** Always prevent default form submission */\r\n preventDefault?: boolean;\r\n /** Prevent default on validation failure (default: true) */\r\n preventDefaultOnFailed?: boolean;\r\n /** Callback invoked when form passes validation */\r\n submitCallback?: () => void;\r\n}\r\n\r\n/**\r\n * Form validation helper that integrates with HTML5 validation.\r\n * Supports error summaries, auto-validation, and custom submit handling.\r\n *\r\n * @example\r\n * // Prevent submission and handle manually\r\n * class MyComponent extends HTMLElement {\r\n * private validator: FormValidator;\r\n *\r\n * connectedCallback() {\r\n * const form = this.querySelector('form');\r\n * this.validator = new FormValidator(form, {\r\n * submitCallback: () => this.handleSubmit()\r\n * });\r\n * }\r\n *\r\n * private async handleSubmit() {\r\n * const data = readData(this.form);\r\n * await fetch('/api/save', { method: 'POST', body: JSON.stringify(data) });\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // With error summary display\r\n * const validator = new FormValidator(form, {\r\n * useSummary: true,\r\n * autoValidate: true\r\n * });\r\n */\r\nexport class FormValidator {\r\n private errorSummary: HTMLDivElement;\r\n\r\n constructor(\r\n private form: HTMLFormElement,\r\n private options?: ValidatorOptions\r\n ) {\r\n if (!this.form) {\r\n throw new Error('Form must be specified.');\r\n }\r\n\r\n this.form.addEventListener('submit', (event) => {\r\n if (\r\n options?.preventDefault ||\r\n this.options?.submitCallback != null\r\n ) {\r\n event.preventDefault();\r\n }\r\n if (this.options?.customChecks) {\r\n this.options.customChecks(form);\r\n }\r\n\r\n if (this.validateForm()) {\r\n this.options?.submitCallback?.apply(this);\r\n } else {\r\n if (options?.preventDefaultOnFailed !== false) {\r\n event.preventDefault();\r\n }\r\n }\r\n });\r\n\r\n if (options?.autoValidate) {\r\n form.addEventListener('input', (/*e: InputEvent*/) => {\r\n this.validateForm();\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Validates all form fields.\r\n * Uses native HTML5 validation and optionally displays an error summary.\r\n *\r\n * @returns true if form is valid, false otherwise\r\n */\r\n public validateForm(): boolean {\r\n const formElements = Array.from(\r\n this.form.querySelectorAll('input,textarea,select')\r\n ) as (HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement)[];\r\n let isFormValid = true;\r\n\r\n if (this.options?.useSummary !== true) {\r\n if (this.form.checkValidity()) {\r\n return true;\r\n }\r\n\r\n this.form.reportValidity();\r\n this.focusFirstErrorElement();\r\n return false;\r\n }\r\n\r\n const errorMessages: string[] = [];\r\n\r\n formElements.forEach((element) => {\r\n if (!element.checkValidity()) {\r\n isFormValid = false;\r\n const fieldName =\r\n getFieldName.call(this, element) ||\r\n element.name ||\r\n 'Unnamed Field';\r\n errorMessages.push(\r\n `${fieldName}: ${element.validationMessage}`\r\n );\r\n }\r\n });\r\n\r\n if (!isFormValid) {\r\n this.displayErrorSummary(errorMessages);\r\n this.focusFirstErrorElement();\r\n } else {\r\n this.clearErrorSummary();\r\n }\r\n\r\n return isFormValid;\r\n }\r\n\r\n /**\r\n * Displays a list of error messages in the summary element.\r\n *\r\n * @param messages - Array of error messages to display\r\n */\r\n public displayErrorSummary(messages: string[]) {\r\n this.clearErrorSummary();\r\n if (!this.errorSummary){\r\n this.createErrorSummary();\r\n }\r\n\r\n const errorList = this.errorSummary.querySelector('ul');\r\n messages.forEach((message) => {\r\n const listItem = document.createElement('li');\r\n listItem.textContent = message;\r\n errorList.appendChild(listItem);\r\n });\r\n }\r\n\r\n private createErrorSummary() {\r\n const errorSummary = document.createElement('div');\r\n errorSummary.className = 'error-summary';\r\n errorSummary.style.color = 'red';\r\n errorSummary.setAttribute('role', 'alert');\r\n errorSummary.setAttribute('aria-live', 'assertive');\r\n errorSummary.setAttribute('aria-atomic', 'true');\r\n this.errorSummary = errorSummary;\r\n\r\n const errorList = document.createElement('ul');\r\n this.errorSummary.appendChild(errorList);\r\n\r\n this.form.prepend(errorSummary);\r\n }\r\n /**\r\n * Adds a single error to the summary display.\r\n *\r\n * @param fieldName - The name of the field with the error\r\n * @param message - The error message\r\n */\r\n public addErrorToSummary(fieldName: string, message: string) {\r\n if (!this.errorSummary){\r\n this.createErrorSummary();\r\n }\r\n const errorList = this.errorSummary.querySelector('ul');\r\n const listItem = document.createElement('li');\r\n listItem.textContent = `${fieldName}: ${message}`;\r\n errorList.appendChild(listItem);\r\n }\r\n\r\n /**\r\n * Clears all errors from the summary display.\r\n */\r\n public clearErrorSummary() {\r\n if (this.errorSummary){\r\n this.errorSummary.querySelector('ul').innerHTML='';\r\n }\r\n }\r\n\r\n private focusFirstErrorElement() {\r\n const firstInvalidElement = this.form.querySelector(':invalid');\r\n if (\r\n firstInvalidElement instanceof HTMLElement &&\r\n document.activeElement !== firstInvalidElement\r\n ) {\r\n firstInvalidElement.focus();\r\n }\r\n }\r\n\r\n /**\r\n * Finds a form element relative to the given element.\r\n * Searches parent first, then direct children.\r\n *\r\n * @param element - The element to search from\r\n * @returns The found form element\r\n * @throws Error if no form is found\r\n *\r\n * @example\r\n * class MyComponent extends HTMLElement {\r\n * connectedCallback() {\r\n * const form = FormValidator.FindForm(this);\r\n * new FormValidator(form);\r\n * }\r\n * }\r\n */\r\n public static FindForm(element: HTMLElement): HTMLFormElement {\r\n if (element.parentElement?.tagName == 'FORM') {\r\n return <HTMLFormElement>element.parentElement;\r\n } else {\r\n for (let i = 0; i < element.children.length; i++) {\r\n const child = element.children[i];\r\n if (child.tagName == 'FORM') {\r\n return <HTMLFormElement>child;\r\n }\r\n }\r\n }\r\n\r\n throw new Error(\r\n 'Parent or a direct child must be a FORM for class ' +\r\n element.constructor.name\r\n );\r\n }\r\n}\r\n", "/**\r\n * Sets form field values from a data object using the name attribute.\r\n * Supports dot notation for accessing nested properties and array handling.\r\n * \r\n * @param form - The HTML form element to populate\r\n * @param data - The data object containing values to set in the form\r\n * \r\n * @example\r\n * // Basic usage with flat object\r\n * const form = document.querySelector('form');\r\n * const data = { name: 'John', email: 'john@example.com' };\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with nested objects via dot notation\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * user: { \r\n * name: 'John', \r\n * contact: { \r\n * email: 'john@example.com' \r\n * } \r\n * } \r\n * };\r\n * // Form has fields with names like \"user.name\" and \"user.contact.email\"\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with simple arrays using [] notation\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * hobbies: ['Reading', 'Cycling', 'Cooking']\r\n * };\r\n * // Form has multiple fields with names like \"hobbies[]\"\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with array of objects using numeric indexers\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * users: [\r\n * { name: 'John', email: 'john@example.com' },\r\n * { name: 'Jane', email: 'jane@example.com' }\r\n * ]\r\n * };\r\n * // Form has fields with names like \"users[0].name\", \"users[1].email\", etc.\r\n * setFormData(form, data);\r\n */\r\nexport function setFormData(form: HTMLFormElement, data: object): void {\r\n const formElements = form.querySelectorAll('[name]');\r\n\r\n formElements.forEach(element => {\r\n\r\n const name = element.getAttribute('name');\r\n if (!name) return;\r\n\r\n // Handle simple array notation (e.g., hobbies[])\r\n if (name.endsWith('[]')) {\r\n const arrayName = name.slice(0, -2);\r\n const arrayValue = getValueByComplexPath(data, arrayName);\r\n\r\n if (Array.isArray(arrayValue)) {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox' || type === 'radio') {\r\n el.checked = arrayValue.includes(el.value);\r\n } else if ('options' in el && boolAttr(element, 'multiple')) {\r\n arrayValue.forEach(val => {\r\n const option = Array.from(el.options as HTMLOptionElement[])\r\n .find((opt: HTMLOptionElement) => opt.value === String(val));\r\n if (option) (option as HTMLOptionElement).selected = true;\r\n });\r\n } else if ('value' in el) {\r\n const allWithName = form.querySelectorAll(`[name=\"${name}\"]`);\r\n const idx = Array.from(allWithName).indexOf(element);\r\n if (idx >= 0 && idx < arrayValue.length) {\r\n el.value = String(arrayValue[idx]);\r\n }\r\n }\r\n }\r\n return;\r\n }\r\n\r\n // Handle complex paths with array indexers and dot notation\r\n const value = getValueByComplexPath(data, name);\r\n if (value === undefined || value === null) return;\r\n\r\n setElementValue(element, value);\r\n });\r\n }\r\n \r\n function getValueByComplexPath(obj: object, path: string): any {\r\n // Handle array indexers like users[0].name\r\n const segments = [];\r\n let currentSegment = '';\r\n let inBrackets = false;\r\n \r\n for (let i = 0; i < path.length; i++) {\r\n const char = path[i];\r\n \r\n if (char === '[' && !inBrackets) {\r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n }\r\n inBrackets = true;\r\n currentSegment += char;\r\n } else if (char === ']' && inBrackets) {\r\n currentSegment += char;\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n inBrackets = false;\r\n } else if (char === '.' && !inBrackets) {\r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n }\r\n } else {\r\n currentSegment += char;\r\n }\r\n }\r\n \r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n }\r\n \r\n return segments.reduce((result, segment) => {\r\n if (!result || typeof result !== 'object') return undefined;\r\n \r\n // Handle array indexer segments like [0]\r\n if (segment.startsWith('[') && segment.endsWith(']')) {\r\n const index = segment.slice(1, -1);\r\n return result[index];\r\n }\r\n \r\n return result[segment];\r\n }, obj);\r\n }\r\n \r\n function getValueByPath(obj: object, path: string): any {\r\n return path.split('.').reduce((o, key) => {\r\n return o && typeof o === 'object' ? o[key] : undefined;\r\n }, obj);\r\n }\r\n \r\n function setElementValue(element: Element, value: any): void {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox') {\r\n el.checked = Boolean(value);\r\n } else if (type === 'radio') {\r\n el.checked = el.value === String(value);\r\n } else if (type === 'date' && value instanceof Date) {\r\n el.value = value.toISOString().split('T')[0];\r\n } else if (type === 'datetime-local' && value instanceof Date) {\r\n const pad = (n: number) => String(n).padStart(2, '0');\r\n el.value = `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}T${pad(value.getHours())}:${pad(value.getMinutes())}`;\r\n } else if ('options' in el && boolAttr(element, 'multiple') && Array.isArray(value)) {\r\n const options = Array.from(el.options as HTMLOptionElement[]);\r\n const vals = value.map(String);\r\n options.forEach((opt: HTMLOptionElement) => {\r\n opt.selected = vals.includes(opt.value);\r\n });\r\n } else if ('value' in el) {\r\n el.value = String(value);\r\n }\r\n }\r\n\r\n function boolAttr(element: Element, name: string): boolean {\r\n const el = element as Record<string, any>;\r\n if (name in el && typeof el[name] === 'boolean') return el[name];\r\n const attr = element.getAttribute(name);\r\n if (attr === null) return false;\r\n if (attr === '' || attr.toLowerCase() === 'true' || attr.toLowerCase() === name) return true;\r\n return false;\r\n }", "/**\r\n * @module ValidationRules\r\n * Form validation rules for use with FormValidator.\r\n * Provides declarative validation through decorators.\r\n *\r\n * Validation messages use the i18n system. Load the 'r-validation' namespace\r\n * for localized error messages:\r\n *\r\n * @example\r\n * await loadNamespace('r-validation');\r\n *\r\n * @example\r\n * // In HTML, use validation attributes\r\n * <input name=\"age\" data-validate=\"required range(0-120)\" />\r\n */\r\n\r\nimport { t } from '../i18n/i18n';\r\n\r\n/**\r\n * Context provided to validators during validation.\r\n */\r\nexport interface ValidationContext {\r\n /** The HTML input type (text, number, email, etc.) */\r\n inputType: string;\r\n /** The data-type attribute value if present */\r\n dataType?: string;\r\n /** Adds an error message to the validation result */\r\n addError(message: string): void;\r\n}\r\n\r\n/**\r\n * Interface for custom validators.\r\n */\r\ninterface Validator {\r\n /**\r\n * Validates the given value.\r\n * @param value - The string value to validate\r\n * @param context - Validation context with type info and error reporting\r\n */\r\n validate(value: string, context: ValidationContext): void;\r\n}\r\n\r\ninterface ValidatorRegistryEntry {\r\n validator: { new (): Validator };\r\n validInputTypes: string[];\r\n}\r\n\r\nconst validators: Map<string, ValidatorRegistryEntry> = new Map();\r\n\r\n/**\r\n * Decorator to register a validator class for a specific validation name.\r\n *\r\n * @param validationName - The name used in data-validate attribute\r\n * @param validInputTypes - Optional list of input types this validator applies to\r\n *\r\n * @example\r\n * @RegisterValidator('email')\r\n * class EmailValidation implements Validator {\r\n * validate(value: string, context: ValidationContext) {\r\n * if (!value.includes('@')) {\r\n * context.addError('Invalid email address');\r\n * }\r\n * }\r\n * }\r\n */\r\nexport function RegisterValidator(validationName: string, validInputTypes: string[] = []) {\r\n return function (target: { new (...args: unknown[]): Validator }) {\r\n validators.set(validationName, { validator: target, validInputTypes });\r\n };\r\n}\r\n\r\n/**\r\n * Looks up a registered validator by name.\r\n *\r\n * @param name - The validator name used in `data-validate`\r\n * @returns The registry entry, or `undefined` if not found\r\n */\r\nexport function getValidator(name: string): ValidatorRegistryEntry | undefined {\r\n return validators.get(name);\r\n}\r\n\r\n/**\r\n * Validates that a field has a non-empty value.\r\n * Use with `data-validate=\"required\"`.\r\n */\r\n@RegisterValidator('required')\r\nexport class RequiredValidation implements Validator {\r\n static create(rule: string): RequiredValidation | null {\r\n return rule === 'required' ? new RequiredValidation() : null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (value.trim() !== ''){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage());\r\n }\r\n\r\n getMessage(): string {\r\n return t('r-validation:required');\r\n }\r\n}\r\n\r\n/**\r\n * Validates that a numeric value falls within a specified range.\r\n * Use with `data-validate=\"range(min-max)\"`.\r\n *\r\n * @example\r\n * <input name=\"age\" type=\"number\" data-validate=\"range(0-120)\" />\r\n */\r\n@RegisterValidator('range', ['number'])\r\nexport class RangeValidation implements Validator {\r\n min: number;\r\n max: number;\r\n\r\n constructor(min: number, max: number) {\r\n this.min = min;\r\n this.max = max;\r\n }\r\n\r\n static create(rule: string): RangeValidation | null {\r\n const rangeMatch = rule.match(/^range\\((-?\\d+(?:\\.\\d+)?)-(-?\\d+(?:\\.\\d+)?)\\)$/);\r\n if (rangeMatch) {\r\n const [, min, max] = rangeMatch;\r\n return new RangeValidation(parseFloat(min), parseFloat(max));\r\n }\r\n return null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (value.trim() === '') return;\r\n\r\n const num = parseFloat(value);\r\n if (!isNaN(num) && num >= this.min && num <= this.max){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage(value));\r\n }\r\n\r\n getMessage(actual: string): string {\r\n return t('r-validation:range', { min: this.min, max: this.max, actual });\r\n }\r\n}\r\n\r\n/**\r\n * Validates that a value contains only numeric digits (0-9).\r\n * Use with `data-validate=\"digits\"`.\r\n */\r\n@RegisterValidator('digits', ['number'])\r\nexport class DigitsValidation implements Validator {\r\n static create(rule: string): DigitsValidation | null {\r\n return rule === 'digits' ? new DigitsValidation() : null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (/^\\d+$/.test(value)){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage());\r\n }\r\n\r\n getMessage(): string {\r\n return t('r-validation:digits');\r\n }\r\n}\r\n"],
5
+ "mappings": "49EAAA,IAAAA,GAAAC,EAAA,CAAAC,GAAAC,KAAA,CAAAA,GAAA,SACI,SAAY,iBACZ,MAAS,+CACb,ICHA,IAAAC,GAAAC,EAAA,CAAAC,GAAAC,KAAA,CAAAA,GAAA,SACI,MAAS,QACT,UAAa,YACb,QAAW,sDACX,OAAU,oDACd,ICLA,IAAAC,GAAAC,EAAA,CAAAC,GAAAC,KAAA,CAAAA,GAAA,SACI,SAAY,0BACZ,MAAS,wDACT,OAAU,2BACd,ICJA,IAAAC,GAAAC,EAAA,CAAAC,GAAAC,KAAA,CAAAA,GAAA,SACI,SAAY,eACZ,MAAS,8CACb,ICHA,IAAAC,GAAAC,EAAA,CAAAC,GAAAC,KAAA,CAAAA,GAAA,SACI,MAAS,OACT,UAAa,UACb,QAAW,2DACX,OAAU,kDACd,ICLA,IAAAC,GAAAC,EAAA,CAAAC,GAAAC,KAAA,CAAAA,GAAA,SACI,SAAY,qCACZ,MAAS,4DACT,OAAU,sBACd,ICJA,IAAAC,GAAA,GAAAC,GAAAD,GAAA,sBAAAE,EAAA,kBAAAC,EAAA,qBAAAC,EAAA,kBAAAC,EAAA,oBAAAC,EAAA,oBAAAC,EAAA,sBAAAC,EAAA,uBAAAC,EAAA,gCAAAC,EAAA,iCAAAC,EAAA,qBAAAC,EAAA,iBAAAC,GAAA,mBAAAC,GAAA,aAAAC,GAAA,gBAAAC,KAAA,eAAAC,GAAAjB,ICqBA,IAAMkB,EAAmB,IAAI,IAa7B,SAASC,GAAcC,EAAkC,CACrD,OAAKF,EAAiB,IAAIE,CAAM,GAC5BF,EAAiB,IAAIE,EAAQ,IAAI,KAAK,YAAYA,CAAM,CAAC,EAEtDF,EAAiB,IAAIE,CAAM,CACtC,CAEA,SAASC,GAAYC,EAAmB,CACpC,OAAOA,EAAE,QAAQ,sBAAuB,MAAM,CAClD,CAmBO,SAASC,GACZC,EACAC,EACAL,EAAiB,KACX,CACN,OAAOI,EAAQ,QACX,2DACA,CAACE,EAAGC,EAAKC,EAAMC,IAAmB,CAC9B,IAAMC,EAAQL,EAAOE,CAAG,EAExB,GAAIC,IAAS,SAAU,CACnB,IAAMG,EAAQ,IAAI,OACd,IAAIV,GAAY,OAAOS,CAAK,CAAC,CAAC,oBAClC,EAAE,KAAKD,CAAc,EACrB,GAAIE,EACA,OAAOA,EAAM,CAAC,EACT,QAAQ,IAAIJ,CAAG,IAAK,OAAOG,CAAK,CAAC,EACjC,QAAQ,IAAK,OAAOA,CAAK,CAAC,EAInC,IAAME,EADQb,GAAcC,CAAM,EACX,OAAOU,CAAK,EAC7BG,EACF,IAAI,OAAO,GAAGD,CAAQ,oBAAoB,EAAE,KAAKH,CAAc,GAC/D,IAAI,OAAO,yBAAyB,EAAE,KAAKA,CAAc,EAC7D,OAAII,EACOA,EAAM,CAAC,EACT,QAAQ,IAAIN,CAAG,IAAK,OAAOG,CAAK,CAAC,EACjC,QAAQ,IAAK,OAAOA,CAAK,CAAC,EAE5B,OAAOA,CAAK,CACvB,CAEA,GAAIF,IAAS,SAAU,CACnB,IAAMM,EAAUb,GAAY,OAAOS,CAAK,CAAC,EACnCG,EACF,IAAI,OAAO,MAAMC,CAAO,oBAAoB,EAAE,KAAKL,CAAc,GACjE,IAAI,OAAO,4BAA4B,EAAE,KAAKA,CAAc,EAChE,OAAOI,EAAQA,EAAM,CAAC,EAAI,OAAOH,CAAK,CAC1C,CAEA,OAAOA,IAAU,OAAY,OAAOA,CAAK,EAAI,IAAIH,CAAG,GACxD,CACJ,CACJ,CAMO,IAAIQ,GAA8BZ,obC7DzC,IAAMa,GAAyB,KAC3BC,EAAwBD,GAE5B,IAAME,GAA6B,CAAC,EAChCC,GAAmD,KAuFhD,SAASC,EAAEC,EAAiBC,EAAsC,CACrE,GAAM,CAACC,EAAWC,CAAG,EAAIH,EAAQ,SAAS,GAAG,EACvCA,EAAQ,MAAM,GAAG,EACjB,CAAC,WAAYA,CAAO,EACpBI,EAAUC,GAAaH,CAAS,IAAIC,CAAG,EAC7C,GAAI,CAACC,EACD,OAAIE,IAAgBA,GAAeH,EAAKD,EAAWK,CAAa,EACzDP,EAEX,GAAI,CACA,OAAOQ,GAAUJ,EAASH,EAAQM,CAAa,CACnD,MAAQ,CACJ,OAAOP,CACX,CACJ,CAOO,SAASS,IAA2B,CACvC,OAAOF,CACX,CCpHO,SAASG,GACZC,EACAC,EACAC,EAGI,CAAC,EACJ,CACD,IAAMC,EAAeH,EAAK,iBAAiB,yBAAyB,EAuBpE,GArBAG,EAAa,QAASC,GAAY,CAE9B,GADI,CAACA,EAAQ,aAAa,MAAM,GAC5BC,EAAYD,EAAS,UAAU,EAAG,OAEtC,IAAME,EAAeF,EAAQ,aAAa,MAAM,EAEhD,GAAI,EAAEE,KAAgBL,GAAW,CAC7B,GAAIC,EAAQ,uBACR,MAAM,IAAI,MACN,eAAeI,CAAY,8CAC/B,EAEJ,MACJ,CAEA,IAAMC,EAAQC,GAAiBJ,CAAO,EAClCG,IAAUE,KAEbR,EAAqCK,CAAY,EAAIC,EAC1D,CAAC,EAEGL,EAAQ,oBAAqB,CAC7B,IAAMQ,EAAiB,IAAI,IAC3BP,EAAa,QAASC,GAAY,CAC1BA,EAAQ,aAAa,MAAM,GAC3BM,EAAe,IAAIN,EAAQ,aAAa,MAAM,CAAE,CAExD,CAAC,EAED,QAAWO,KAAQV,EACf,GACI,OAAOA,EAASU,CAAI,GAAM,YAC1B,OAAO,UAAU,eAAe,KAAKV,EAAUU,CAAI,GACnD,CAACD,EAAe,IAAIC,CAAI,EAExB,MAAM,IAAI,MACN,mBAAmBA,CAAI,8BAC3B,CAGZ,CAEA,OAAOV,CACX,CAiCO,SAASW,EAAiBR,EAAqC,CAClE,IAAMS,EAAWT,EAAQ,aAAa,WAAW,EACjD,OAAIS,EACOC,EAA4BD,CAAQ,EAG3CT,aAAmB,iBACZW,EAA6BX,EAAQ,IAAiB,EAI7D,YAAaA,GAAW,OAAQA,EAAgB,SAAY,UACrDY,EAGHC,GAAQA,CACpB,CAuCO,SAASC,GAAsClB,EAAyB,CAC3E,IAAMmB,EAAgC,CAAC,EACjCC,EAAW,IAAI,SAASpB,CAAI,EAC5BqB,EAAO,IAAI,IAEjBD,EAAS,QAAQ,CAACE,EAAGC,IAAS,CAC1B,GAAIF,EAAK,IAAIE,CAAI,EAAG,OACpBF,EAAK,IAAIE,CAAI,EAEb,IAAMC,EAASJ,EAAS,OAAOG,CAAI,EAC7BnB,EAAUJ,EAAK,SAAS,UAAUuB,CAAI,EACtCE,EAAYrB,EAAUQ,EAAiBR,CAAsB,EAAKsB,GAAcA,EAEtF,GAAIF,EAAO,SAAW,EAAG,CACrB,IAAME,EAAIF,EAAO,CAAC,EAClBL,EAAKI,CAAI,EAAI,OAAOG,GAAM,SAAWD,EAAUC,CAAC,EAAIA,CACxD,MACIP,EAAKI,CAAI,EAAIC,EAAO,IAAIE,GAAK,OAAOA,GAAM,SAAWD,EAAUC,CAAC,EAAIA,CAAC,CAE7E,CAAC,EAED,QAASC,EAAI,EAAGA,EAAI3B,EAAK,SAAS,OAAQ2B,IAAK,CAC3C,IAAMC,EAAK5B,EAAK,SAAS2B,CAAC,EACtBC,EAAG,OAAS,YAAcA,EAAG,MAAQ,CAACP,EAAK,IAAIO,EAAG,IAAI,IACtDP,EAAK,IAAIO,EAAG,IAAI,EAChBT,EAAKS,EAAG,IAAI,EAAI,GAExB,CAEA,OAAOT,CACX,CAoCO,SAASH,EAAiBT,EAAqC,CAClE,GAAI,CAACA,GAASA,GAAS,GACnB,OAGJ,IAAMsB,EAAQtB,EAAM,YAAY,EAEhC,GAAIsB,IAAU,QAAUA,IAAU,MAAQ,OAAOtB,CAAK,EAAI,EACtD,MAAO,GAGX,GAAIsB,IAAU,SAAWA,IAAU,OAAS,OAAOtB,CAAK,GAAK,EACzD,MAAO,GAGX,MAAM,IAAI,MAAM,4BAA8BA,EAAQ,eAAe,CACzE,CASO,SAASuB,EAAgBvB,EAAoC,CAChE,GAAI,CAACA,GAASA,GAAS,GACnB,OAEJ,IAAMwB,EAAK,OAAOxB,CAAK,EACvB,GAAI,CAAC,MAAMwB,CAAE,EACT,OAAOA,EAEX,MAAM,IAAI,MAAM,4BAA8BxB,EAAQ,cAAc,CACxE,CAWA,SAASyB,GAAmBC,EAA8C,CAEtE,OADc,IAAI,KAAK,eAAeA,CAAM,EAAE,cAAc,IAAI,KAAK,KAAM,EAAG,EAAE,CAAC,EAE5E,OAAQC,GACLA,EAAE,OAAS,OAASA,EAAE,OAAS,SAAWA,EAAE,OAAS,MAAM,EAC9D,IAAIA,GAAKA,EAAE,IAAI,CACxB,CAqBO,SAASC,EAAc5B,EAAiC,CAC3D,GAAI,CAACA,GAASA,IAAU,GAAI,OAE5B,GAAI,0BAA0B,KAAKA,CAAK,EAAG,CACvC,IAAM6B,EAAO,IAAI,KAAK7B,CAAK,EAC3B,GAAI,CAAC,MAAM6B,EAAK,QAAQ,CAAC,EAAG,OAAOA,CACvC,CAEA,IAAMC,EAAe9B,EAAM,MAAM,WAAW,EAC5C,GAAI8B,EAAa,QAAU,GAAKA,EAAa,MAAMH,GAAK,QAAQ,KAAKA,CAAC,CAAC,EAAG,CACtE,IAAMD,EAASK,GAAiB,EAC1BC,EAAQP,GAAmBC,CAAM,EACjCO,EAAiC,CAAC,EAKxC,GAJAD,EAAM,QAAQ,CAACE,EAAMd,IAAM,CACvBa,EAAOC,CAAI,EAAI,SAASJ,EAAaV,CAAC,EAAG,EAAE,CAC/C,CAAC,EAEGa,EAAO,OAAS,QAAaA,EAAO,QAAU,QAAaA,EAAO,MAAQ,OAAW,CACjFA,EAAO,KAAO,MAAKA,EAAO,MAAQ,KACtC,IAAMJ,EAAO,IAAI,KAAKI,EAAO,KAAMA,EAAO,MAAQ,EAAGA,EAAO,GAAG,EAC/D,GAAI,CAAC,MAAMJ,EAAK,QAAQ,CAAC,EAAG,OAAOA,CACvC,CACJ,CAEA,IAAMA,EAAO,IAAI,KAAK7B,CAAK,EAC3B,GAAI,MAAM6B,EAAK,QAAQ,CAAC,EACpB,MAAM,IAAI,MAAM,qBAAqB,EAEzC,OAAOA,CACX,CAQO,SAAStB,EAA4BD,EAAmC,CAC3E,OAAQA,EAAU,CACd,IAAK,UACD,OAAOG,EACX,IAAK,SACD,OAAOc,EACX,IAAK,OACD,OAAOK,EACX,IAAK,SACD,OAAQ5B,GAAW,CAACA,GAASA,GAAS,GAAK,OAAYA,EAC3D,QACI,MAAM,IAAI,MAAM,sBAAsBM,CAAQ,IAAI,CAC1D,CACJ,CASO,SAASE,EAA6B2B,EAAqC,CAC9E,OAAQA,EAAW,CACf,IAAK,WACD,OAAO1B,EAEX,IAAK,SACD,OAAOc,EAEX,IAAK,OACL,IAAK,iBACD,OAAOK,EAEX,IAAK,QACD,OAAQ5B,GAAU,CACd,GAAM,CAACoC,EAAMC,CAAK,EAAIrC,EAAM,MAAM,GAAG,EAAE,IAAI,MAAM,EACjD,OAAO,IAAI,KAAKoC,EAAMC,EAAQ,CAAC,CACnC,EAEJ,IAAK,OACD,OAAQrC,GAAU,CACd,GAAM,CAACoC,EAAME,CAAI,EAAItC,EAAM,MAAM,IAAI,EAAE,IAAI,MAAM,EACjD,MAAO,CAAE,KAAAoC,EAAM,KAAAE,CAAK,CACxB,EAEJ,IAAK,OACD,OAAQtC,GAAU,CACd,GAAM,CAACuC,EAAOC,EAASC,EAAU,CAAC,EAAIzC,EAAM,MAAM,GAAG,EAAE,IAAI,MAAM,EACjE,MAAO,CAAE,MAAAuC,EAAO,QAAAC,EAAS,QAAAC,CAAQ,CACrC,EAEJ,QACI,OAAQzC,GAAW,CAACA,GAASA,GAAS,GAAK,OAAYA,CAC/D,CACJ,CAEA,SAASF,EAAYD,EAAkBmB,EAAuB,CAC1D,IAAMK,EAAKxB,EACX,GAAImB,KAAQK,GAAM,OAAOA,EAAGL,CAAI,GAAM,UAAW,OAAOK,EAAGL,CAAI,EAC/D,IAAM0B,EAAO7C,EAAQ,aAAamB,CAAI,EACtC,OAAI0B,IAAS,KAAa,GACtBA,IAAS,IAAMA,EAAK,YAAY,IAAM,QAAUA,EAAK,YAAY,IAAM1B,CAE/E,CAEA,IAAMd,GAAO,OAAO,MAAM,EAE1B,SAASD,GAAiBJ,EAA2B,CACjD,IAAMwB,EAAKxB,EACLqC,EAAOb,EAAG,MAAQxB,EAAQ,aAAa,MAAM,GAAK,GAExD,GAAIqC,IAAS,WACT,OAAOpC,EAAYD,EAAS,SAAS,EAGzC,GAAIqC,IAAS,QACT,OAAKpC,EAAYD,EAAS,SAAS,EAC5BwB,EAAG,MADmCnB,GAIjD,GAAIgC,IAAS,SACT,OAAOb,EAAG,MAAQ,OAAOA,EAAG,KAAK,EAAI,KAGzC,GAAIa,IAAS,OACT,OAAOb,EAAG,MAAQ,IAAI,KAAKA,EAAG,KAAK,EAAI,KAG3C,GAAI,oBAAqBA,GAAMvB,EAAYD,EAAS,UAAU,EAC1D,OAAO,MAAM,KAAKwB,EAAG,eAAgD,EAChE,IAAKsB,GAAyBA,EAAE,KAAK,EAG9C,GAAI,UAAWtB,EACX,OAAOA,EAAG,KAIlB,CCzbA,SAASuB,GAAaC,EAAqC,CACvD,IAAMC,EAAKD,EAAQ,aAAa,IAAI,EACpC,GAAIC,EAAI,CACJ,IAAMC,EAAOF,EAAQ,QAAQ,MAAM,EACnC,GAAIE,EAAM,CACN,IAAMC,EAAQD,EAAK,cAAc,cAAcD,CAAE,IAAI,EACrD,GAAIE,EACA,OAAOA,EAAM,aAAa,KAAK,GAAK,IAE5C,CACJ,CAEA,OAAO,IACX,CAiDO,IAAMC,EAAN,KAAoB,CAGvB,YACYF,EACAG,EACV,CAFU,UAAAH,EACA,aAAAG,EAER,GAAI,CAAC,KAAK,KACN,MAAM,IAAI,MAAM,yBAAyB,EAG7C,KAAK,KAAK,iBAAiB,SAAWC,GAAU,EAExCD,GAAS,gBACT,KAAK,SAAS,gBAAkB,OAEhCC,EAAM,eAAe,EAErB,KAAK,SAAS,cACd,KAAK,QAAQ,aAAaJ,CAAI,EAG9B,KAAK,aAAa,EAClB,KAAK,SAAS,gBAAgB,MAAM,IAAI,EAEpCG,GAAS,yBAA2B,IACpCC,EAAM,eAAe,CAGjC,CAAC,EAEGD,GAAS,cACTH,EAAK,iBAAiB,QAAS,IAAuB,CAClD,KAAK,aAAa,CACtB,CAAC,CAET,CAQO,cAAwB,CAC3B,IAAMK,EAAe,MAAM,KACvB,KAAK,KAAK,iBAAiB,uBAAuB,CACtD,EACIC,EAAc,GAElB,GAAI,KAAK,SAAS,aAAe,GAC7B,OAAI,KAAK,KAAK,cAAc,EACjB,IAGX,KAAK,KAAK,eAAe,EACzB,KAAK,uBAAuB,EACrB,IAGX,IAAMC,EAA0B,CAAC,EAEjC,OAAAF,EAAa,QAASP,GAAY,CAC9B,GAAI,CAACA,EAAQ,cAAc,EAAG,CAC1BQ,EAAc,GACd,IAAME,EACFX,GAAa,KAAK,KAAMC,CAAO,GAC/BA,EAAQ,MACR,gBACJS,EAAc,KACV,GAAGC,CAAS,KAAKV,EAAQ,iBAAiB,EAC9C,CACJ,CACJ,CAAC,EAEIQ,EAID,KAAK,kBAAkB,GAHvB,KAAK,oBAAoBC,CAAa,EACtC,KAAK,uBAAuB,GAKzBD,CACX,CAOO,oBAAoBG,EAAoB,CAC3C,KAAK,kBAAkB,EAClB,KAAK,cACN,KAAK,mBAAmB,EAG5B,IAAMC,EAAY,KAAK,aAAa,cAAc,IAAI,EACtDD,EAAS,QAASE,GAAY,CAC1B,IAAMC,EAAW,SAAS,cAAc,IAAI,EAC5CA,EAAS,YAAcD,EACvBD,EAAU,YAAYE,CAAQ,CAClC,CAAC,CACL,CAEQ,oBAAqB,CACzB,IAAMC,EAAe,SAAS,cAAc,KAAK,EACjDA,EAAa,UAAY,gBACzBA,EAAa,MAAM,MAAQ,MAC3BA,EAAa,aAAa,OAAQ,OAAO,EACzCA,EAAa,aAAa,YAAa,WAAW,EAClDA,EAAa,aAAa,cAAe,MAAM,EAC/C,KAAK,aAAeA,EAEpB,IAAMH,EAAY,SAAS,cAAc,IAAI,EAC7C,KAAK,aAAa,YAAYA,CAAS,EAEvC,KAAK,KAAK,QAAQG,CAAY,CAClC,CAOO,kBAAkBL,EAAmBG,EAAiB,CACpD,KAAK,cACN,KAAK,mBAAmB,EAE5B,IAAMD,EAAY,KAAK,aAAa,cAAc,IAAI,EAChDE,EAAW,SAAS,cAAc,IAAI,EAC5CA,EAAS,YAAc,GAAGJ,CAAS,KAAKG,CAAO,GAC/CD,EAAU,YAAYE,CAAQ,CAClC,CAKO,mBAAoB,CACnB,KAAK,eACL,KAAK,aAAa,cAAc,IAAI,EAAE,UAAU,GAExD,CAEQ,wBAAyB,CAC7B,IAAME,EAAsB,KAAK,KAAK,cAAc,UAAU,EAE1DA,aAA+B,aAC/B,SAAS,gBAAkBA,GAE3BA,EAAoB,MAAM,CAElC,CAkBA,OAAc,SAAShB,EAAuC,CAC1D,GAAIA,EAAQ,eAAe,SAAW,OAClC,OAAwBA,EAAQ,cAEhC,QAASiB,EAAI,EAAGA,EAAIjB,EAAQ,SAAS,OAAQiB,IAAK,CAC9C,IAAMC,EAAQlB,EAAQ,SAASiB,CAAC,EAChC,GAAIC,EAAM,SAAW,OACjB,OAAwBA,CAEhC,CAGJ,MAAM,IAAI,MACN,qDACIlB,EAAQ,YAAY,IAC5B,CACJ,CACJ,EC/NO,SAASmB,GAAYC,EAAuBC,EAAoB,CAC9CD,EAAK,iBAAiB,QAAQ,EAEtC,QAAQE,GAAW,CAE9B,IAAMC,EAAOD,EAAQ,aAAa,MAAM,EACxC,GAAI,CAACC,EAAM,OAGX,GAAIA,EAAK,SAAS,IAAI,EAAG,CACvB,IAAMC,EAAYD,EAAK,MAAM,EAAG,EAAE,EAC5BE,EAAaC,GAAsBL,EAAMG,CAAS,EAExD,GAAI,MAAM,QAAQC,CAAU,EAAG,CAC7B,IAAME,EAAKL,EACLM,EAAOD,EAAG,MAAQL,EAAQ,aAAa,MAAM,GAAK,GAExD,GAAIM,IAAS,YAAcA,IAAS,QAClCD,EAAG,QAAUF,EAAW,SAASE,EAAG,KAAK,UAChC,YAAaA,GAAME,GAASP,EAAS,UAAU,EACxDG,EAAW,QAAQK,GAAO,CACxB,IAAMC,EAAS,MAAM,KAAKJ,EAAG,OAA8B,EACxD,KAAMK,GAA2BA,EAAI,QAAU,OAAOF,CAAG,CAAC,EACzDC,IAASA,EAA6B,SAAW,GACvD,CAAC,UACQ,UAAWJ,EAAI,CACxB,IAAMM,EAAcb,EAAK,iBAAiB,UAAUG,CAAI,IAAI,EACtDW,EAAM,MAAM,KAAKD,CAAW,EAAE,QAAQX,CAAO,EAC/CY,GAAO,GAAKA,EAAMT,EAAW,SAC/BE,EAAG,MAAQ,OAAOF,EAAWS,CAAG,CAAC,EAErC,CACF,CACA,MACF,CAGA,IAAMC,EAAQT,GAAsBL,EAAME,CAAI,EACnBY,GAAU,MAErCC,GAAgBd,EAASa,CAAK,CAChC,CAAC,CACH,CAEA,SAAST,GAAsBW,EAAaC,EAAmB,CAE7D,IAAMC,EAAW,CAAC,EACdC,EAAiB,GACjBC,EAAa,GAEjB,QAASC,EAAI,EAAGA,EAAIJ,EAAK,OAAQI,IAAK,CACpC,IAAMC,EAAOL,EAAKI,CAAC,EAEfC,IAAS,KAAO,CAACF,GACfD,IACFD,EAAS,KAAKC,CAAc,EAC5BA,EAAiB,IAEnBC,EAAa,GACbD,GAAkBG,GACTA,IAAS,KAAOF,GACzBD,GAAkBG,EAClBJ,EAAS,KAAKC,CAAc,EAC5BA,EAAiB,GACjBC,EAAa,IACJE,IAAS,KAAO,CAACF,EACtBD,IACFD,EAAS,KAAKC,CAAc,EAC5BA,EAAiB,IAGnBA,GAAkBG,CAEtB,CAEA,OAAIH,GACFD,EAAS,KAAKC,CAAc,EAGvBD,EAAS,OAAO,CAACK,EAAQC,IAAY,CAC1C,GAAI,GAACD,GAAU,OAAOA,GAAW,UAGjC,IAAIC,EAAQ,WAAW,GAAG,GAAKA,EAAQ,SAAS,GAAG,EAAG,CACpD,IAAMC,EAAQD,EAAQ,MAAM,EAAG,EAAE,EACjC,OAAOD,EAAOE,CAAK,CACrB,CAEA,OAAOF,EAAOC,CAAO,EACvB,EAAGR,CAAG,CACR,CAQA,SAASU,GAAgBC,EAAkBC,EAAkB,CAC3D,IAAMC,EAAKF,EACLG,EAAOD,EAAG,MAAQF,EAAQ,aAAa,MAAM,GAAK,GAExD,GAAIG,IAAS,WACXD,EAAG,QAAU,EAAQD,UACZE,IAAS,QAClBD,EAAG,QAAUA,EAAG,QAAU,OAAOD,CAAK,UAC7BE,IAAS,QAAUF,aAAiB,KAC7CC,EAAG,MAAQD,EAAM,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,UAClCE,IAAS,kBAAoBF,aAAiB,KAAM,CAC7D,IAAMG,EAAOC,GAAc,OAAOA,CAAC,EAAE,SAAS,EAAG,GAAG,EACpDH,EAAG,MAAQ,GAAGD,EAAM,YAAY,CAAC,IAAIG,EAAIH,EAAM,SAAS,EAAI,CAAC,CAAC,IAAIG,EAAIH,EAAM,QAAQ,CAAC,CAAC,IAAIG,EAAIH,EAAM,SAAS,CAAC,CAAC,IAAIG,EAAIH,EAAM,WAAW,CAAC,CAAC,EAC5I,SAAW,YAAaC,GAAMI,GAASN,EAAS,UAAU,GAAK,MAAM,QAAQC,CAAK,EAAG,CACnF,IAAMM,EAAU,MAAM,KAAKL,EAAG,OAA8B,EACtDM,EAAOP,EAAM,IAAI,MAAM,EAC7BM,EAAQ,QAASE,GAA2B,CAC1CA,EAAI,SAAWD,EAAK,SAASC,EAAI,KAAK,CACxC,CAAC,CACH,KAAW,UAAWP,IACpBA,EAAG,MAAQ,OAAOD,CAAK,EAE3B,CAEA,SAASK,GAASN,EAAkBU,EAAuB,CACzD,IAAMR,EAAKF,EACX,GAAIU,KAAQR,GAAM,OAAOA,EAAGQ,CAAI,GAAM,UAAW,OAAOR,EAAGQ,CAAI,EAC/D,IAAMC,EAAOX,EAAQ,aAAaU,CAAI,EACtC,OAAIC,IAAS,KAAa,GACtBA,IAAS,IAAMA,EAAK,YAAY,IAAM,QAAUA,EAAK,YAAY,IAAMD,CAE7E,CClIF,IAAME,GAAkD,IAAI,IAkBrD,SAASC,EAAkBC,EAAwBC,EAA4B,CAAC,EAAG,CACtF,OAAO,SAAUC,EAAiD,CAC9DJ,GAAW,IAAIE,EAAgB,CAAE,UAAWE,EAAQ,gBAAAD,CAAgB,CAAC,CACzE,CACJ,CAQO,SAASE,GAAaC,EAAkD,CAC3E,OAAON,GAAW,IAAIM,CAAI,CAC9B,CA/EA,IAAAC,GAAAC,EAqFAD,GAAA,CAACN,EAAkB,UAAU,GACtB,IAAMQ,EAAN,MAAMA,CAAwC,CACjD,OAAO,OAAOC,EAAyC,CACnD,OAAOA,IAAS,WAAa,IAAID,EAAuB,IAC5D,CAEA,SAASE,EAAeC,EAA4B,CAC5CD,EAAM,KAAK,IAAM,IAIrBC,EAAQ,SAAS,KAAK,WAAW,CAAC,CACtC,CAEA,YAAqB,CACjB,OAAOC,EAAE,uBAAuB,CACpC,CACJ,EAhBOL,EAAAM,EAAA,MAAML,EAANM,EAAAP,EAAA,uBADPD,GACaE,GAANO,EAAAR,EAAA,EAAMC,GAAN,IAAMQ,EAANR,EAtFPS,GAAAV,EA+GAU,GAAA,CAACjB,EAAkB,QAAS,CAAC,QAAQ,CAAC,GAC/B,IAAMkB,EAAN,MAAMA,CAAqC,CAI9C,YAAYC,EAAaC,EAAa,CAHtC,gBACA,gBAGI,KAAK,IAAMD,EACX,KAAK,IAAMC,CACf,CAEA,OAAO,OAAOX,EAAsC,CAChD,IAAMY,EAAaZ,EAAK,MAAM,gDAAgD,EAC9E,GAAIY,EAAY,CACZ,GAAM,CAAC,CAAEF,EAAKC,CAAG,EAAIC,EACrB,OAAO,IAAIH,EAAgB,WAAWC,CAAG,EAAG,WAAWC,CAAG,CAAC,CAC/D,CACA,OAAO,IACX,CAEA,SAASV,EAAeC,EAA4B,CAChD,GAAID,EAAM,KAAK,IAAM,GAAI,OAEzB,IAAMY,EAAM,WAAWZ,CAAK,EACxB,CAAC,MAAMY,CAAG,GAAKA,GAAO,KAAK,KAAOA,GAAO,KAAK,KAIlDX,EAAQ,SAAS,KAAK,WAAWD,CAAK,CAAC,CAC3C,CAEA,WAAWa,EAAwB,CAC/B,OAAOX,EAAE,qBAAsB,CAAE,IAAK,KAAK,IAAK,IAAK,KAAK,IAAK,OAAAW,CAAO,CAAC,CAC3E,CACJ,EAhCOhB,EAAAM,EAAA,MAAMK,EAANJ,EAAAP,EAAA,oBADPU,GACaC,GAANH,EAAAR,EAAA,EAAMW,GAAN,IAAMM,EAANN,EAhHPO,GAAAlB,EAsJAkB,GAAA,CAACzB,EAAkB,SAAU,CAAC,QAAQ,CAAC,GAChC,IAAM0B,EAAN,MAAMA,CAAsC,CAC/C,OAAO,OAAOjB,EAAuC,CACjD,OAAOA,IAAS,SAAW,IAAIiB,EAAqB,IACxD,CAEA,SAAShB,EAAeC,EAA4B,CAC5C,QAAQ,KAAKD,CAAK,GAItBC,EAAQ,SAAS,KAAK,WAAW,CAAC,CACtC,CAEA,YAAqB,CACjB,OAAOC,EAAE,qBAAqB,CAClC,CACJ,EAhBOL,EAAAM,EAAA,MAAMa,EAANZ,EAAAP,EAAA,qBADPkB,GACaC,GAANX,EAAAR,EAAA,EAAMmB,GAAN,IAAMC,EAAND",
6
+ "names": ["require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "index_exports", "__export", "BooleanConverter", "DateConverter", "DigitsValidation", "FormValidator", "NumberConverter", "RangeValidation", "RegisterValidator", "RequiredValidation", "createConverterFromDataType", "createConverterFromInputType", "getDataConverter", "getValidator", "mapFormToClass", "readData", "setFormData", "__toCommonJS", "pluralRulesCache", "getPluralRule", "locale", "escapeRegex", "s", "defaultFormatICU", "message", "values", "_", "key", "type", "categoriesPart", "value", "exact", "category", "match", "escaped", "formatICU", "fallbackLocale", "currentLocale", "translations", "missingHandler", "t", "fullKey", "values", "namespace", "key", "message", "translations", "missingHandler", "currentLocale", "formatICU", "getCurrentLocale", "mapFormToClass", "form", "instance", "options", "formElements", "element", "booleanAttr", "propertyName", "value", "readElementValue", "SKIP", "formFieldNames", "prop", "getDataConverter", "dataType", "createConverterFromDataType", "createConverterFromInputType", "BooleanConverter", "str", "readData", "data", "formData", "seen", "_", "name", "values", "converter", "v", "i", "el", "lower", "NumberConverter", "nr", "getLocaleDateOrder", "locale", "p", "DateConverter", "date", "numericParts", "getCurrentLocale", "order", "mapped", "type", "inputType", "year", "month", "week", "hours", "minutes", "seconds", "attr", "o", "getFieldName", "element", "id", "form", "label", "FormValidator", "options", "event", "formElements", "isFormValid", "errorMessages", "fieldName", "messages", "errorList", "message", "listItem", "errorSummary", "firstInvalidElement", "i", "child", "setFormData", "form", "data", "element", "name", "arrayName", "arrayValue", "getValueByComplexPath", "el", "type", "boolAttr", "val", "option", "opt", "allWithName", "idx", "value", "setElementValue", "obj", "path", "segments", "currentSegment", "inBrackets", "i", "char", "result", "segment", "index", "setElementValue", "element", "value", "el", "type", "pad", "n", "boolAttr", "options", "vals", "opt", "name", "attr", "validators", "RegisterValidator", "validationName", "validInputTypes", "target", "getValidator", "name", "_RequiredValidation_decorators", "_init", "_RequiredValidation", "rule", "value", "context", "t", "__decoratorStart", "__decorateElement", "__runInitializers", "RequiredValidation", "_RangeValidation_decorators", "_RangeValidation", "min", "max", "rangeMatch", "num", "actual", "RangeValidation", "_DigitsValidation_decorators", "_DigitsValidation", "DigitsValidation"]
7
+ }
@@ -0,0 +1,2 @@
1
+ var Z=Object.create;var w=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var Te=Object.getOwnPropertyNames;var Fe=Object.getPrototypeOf,Me=Object.prototype.hasOwnProperty;var _=(t,e)=>(e=Symbol[t])?e:Symbol.for("Symbol."+t),T=t=>{throw TypeError(t)};var Ce=(t,e,r)=>e in t?w(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r;var J=(t,e)=>w(t,"name",{value:e,configurable:!0});var ee=t=>e=>{var r=t[e];if(r)return r();throw new Error("Module not found in bundle: "+e)};var g=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Se=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Te(e))!Me.call(t,o)&&o!==r&&w(t,o,{get:()=>e[o],enumerable:!(n=K(e,o))||n.enumerable});return t};var y=(t,e,r)=>(r=t!=null?Z(Fe(t)):{},Se(e||!t||!t.__esModule?w(r,"default",{value:t,enumerable:!0}):r,t));var F=t=>[,,,Z(t?.[_("metadata")]??null)],te=["class","method","getter","setter","accessor","field","value","get","set"],v=t=>t!==void 0&&typeof t!="function"?T("Function expected"):t,Le=(t,e,r,n,o)=>({kind:te[t],name:e,metadata:n,addInitializer:a=>r._?T("Already initialized"):o.push(v(a||null))}),ke=(t,e)=>Ce(e,_("metadata"),t[3]),M=(t,e,r,n)=>{for(var o=0,a=t[e>>1],i=a&&a.length;o<i;o++)e&1?a[o].call(r):n=a[o].call(r,n);return n},C=(t,e,r,n,o,a)=>{var i,s,u,c,p,l=e&7,x=!!(e&8),f=!!(e&16),N=l>3?t.length+1:l?x?1:2:0,Y=te[l+5],G=l>3&&(t[N-1]=[]),we=t[N]||(t[N]=[]),m=l&&(!f&&!x&&(o=o.prototype),l<5&&(l>3||!f)&&K(l<4?o:{get[r](){return Q(this,a)},set[r](d){return X(this,a,d)}},r));l?f&&l<4&&J(a,(l>2?"set ":l>1?"get ":"")+r):J(o,r);for(var A=n.length-1;A>=0;A--)c=Le(l,r,u={},t[3],we),l&&(c.static=x,c.private=f,p=c.access={has:f?d=>De(o,d):d=>r in d},l^3&&(p.get=f?d=>(l^1?Q:Ne)(d,o,l^4?a:m.get):d=>d[r]),l>2&&(p.set=f?(d,H)=>X(d,o,H,l^4?a:m.set):(d,H)=>d[r]=H)),s=(0,n[A])(l?l<4?f?a:m[Y]:l>4?void 0:{get:m.get,set:m.set}:o,c),u._=1,l^4||s===void 0?v(s)&&(l>4?G.unshift(s):l?f?a=s:m[Y]=s:o=s):typeof s!="object"||s===null?T("Object expected"):(v(i=s.get)&&(m.get=i),v(i=s.set)&&(m.set=i),v(i=s.init)&&G.unshift(i));return l||ke(t,o),m&&w(o,r,m),f?l^4?a:m:o};var R=(t,e,r)=>e.has(t)||T("Cannot "+r),De=(t,e)=>Object(e)!==e?T('Cannot use the "in" operator on this value'):t.has(e),Q=(t,e,r)=>(R(t,e,"read from private field"),r?r.call(t):e.get(t));var X=(t,e,r,n)=>(R(t,e,"write to private field"),n?n.call(t,r):e.set(t,r),r),Ne=(t,e,r)=>(R(t,e,"access private method"),r);var oe=g((Ke,Re)=>{Re.exports={greeting:"Hello, {name}!",items:"{count, plural, one {# item} other {# items}}"}});var ae=g((_e,$e)=>{$e.exports={today:"today",yesterday:"yesterday",daysAgo:"{count, plural, one {# day ago} other {# days ago}}",pieces:"{count, plural, =0 {none} one {one} other {# pcs}}"}});var ie=g((et,Oe)=>{Oe.exports={required:"This field is required.",range:"Number must be between {min} and {max}, was {actual}.",digits:"Please enter only digits."}});var se=g((tt,Ve)=>{Ve.exports={greeting:"Hej, {name}!",items:"{count, plural, one {# sak} other {# saker}}"}});var le=g((rt,Ie)=>{Ie.exports={today:"idag",yesterday:"ig\xE5r",daysAgo:"{count, plural, one {# dag sedan} other {# dagar sedan}}",pieces:"{count, plural, =0 {inga} one {en} other {# st}}"}});var ce=g((nt,Pe)=>{Pe.exports={required:"Detta f\xE4lt \xE4r obligatoriskt.",range:"Talet m\xE5ste vara mellan {min} och {max}, var {actual}.",digits:"Ange endast siffror."}});var $=new Map;function Ae(t){return $.has(t)||$.set(t,new Intl.PluralRules(t)),$.get(t)}function re(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function He(t,e,r="en"){return t.replace(/\{(\w+)(?:, (plural|select),((?:[^{}]*\{[^{}]*\})+))?\}/g,(n,o,a,i)=>{let s=e[o];if(a==="plural"){let u=new RegExp(`=${re(String(s))}\\s*\\{([^{}]*)\\}`).exec(i);if(u)return u[1].replace(`{${o}}`,String(s)).replace("#",String(s));let p=Ae(r).select(s),l=new RegExp(`${p}\\s*\\{([^{}]*)\\}`).exec(i)||new RegExp("other\\s*\\{([^{}]*)\\}").exec(i);return l?l[1].replace(`{${o}}`,String(s)).replace("#",String(s)):String(s)}if(a==="select"){let u=re(String(s)),c=new RegExp(`\\b${u}\\s*\\{([^{}]*)\\}`).exec(i)||new RegExp("\\bother\\s*\\{([^{}]*)\\}").exec(i);return c?c[1]:String(s)}return s!==void 0?String(s):`{${o}}`})}var ne=He;var it=ee({"./locales/en/r-common.json":()=>Promise.resolve().then(()=>y(oe())),"./locales/en/r-pipes.json":()=>Promise.resolve().then(()=>y(ae())),"./locales/en/r-validation.json":()=>Promise.resolve().then(()=>y(ie())),"./locales/sv/r-common.json":()=>Promise.resolve().then(()=>y(se())),"./locales/sv/r-pipes.json":()=>Promise.resolve().then(()=>y(le())),"./locales/sv/r-validation.json":()=>Promise.resolve().then(()=>y(ce()))});var qe="en",O=qe;var je={},ue=null;function S(t,e){let[r,n]=t.includes(":")?t.split(":"):["r-common",t],o=je[r]?.[n];if(!o)return ue&&ue(n,r,O),t;try{return ne(o,e,O)}catch{return t}}function de(){return O}function Be(t,e,r={}){let n=t.querySelectorAll("input, select, textarea");if(n.forEach(o=>{if(!o.hasAttribute("name")||L(o,"disabled"))return;let a=o.getAttribute("name");if(!(a in e)){if(r.throwOnMissingProperty)throw new Error(`Form field "${a}" has no matching property in class instance`);return}let i=ze(o);i!==ge&&(e[a]=i)}),r.throwOnMissingField){let o=new Set;n.forEach(a=>{a.hasAttribute("name")&&o.add(a.getAttribute("name"))});for(let a in e)if(typeof e[a]!="function"&&Object.prototype.hasOwnProperty.call(e,a)&&!o.has(a))throw new Error(`Class property "${a}" has no matching form field`)}return e}function me(t){let e=t.getAttribute("data-type");return e?fe(e):t instanceof HTMLInputElement?pe(t.type):"checked"in t&&typeof t.checked=="boolean"?k:r=>r}function Ue(t){let e={},r=new FormData(t),n=new Set;r.forEach((o,a)=>{if(n.has(a))return;n.add(a);let i=r.getAll(a),s=t.elements.namedItem(a),u=s?me(s):c=>c;if(i.length===1){let c=i[0];e[a]=typeof c=="string"?u(c):c}else e[a]=i.map(c=>typeof c=="string"?u(c):c)});for(let o=0;o<t.elements.length;o++){let a=t.elements[o];a.type==="checkbox"&&a.name&&!n.has(a.name)&&(n.add(a.name),e[a.name]=!1)}return e}function k(t){if(!t||t=="")return;let e=t.toLowerCase();if(e==="true"||e==="on"||Number(t)>0)return!0;if(e==="false"||e==="off"||Number(t)<=0)return!1;throw new Error("Could not convert value '"+t+"' to boolean.")}function V(t){if(!t||t=="")return;let e=Number(t);if(!isNaN(e))return e;throw new Error("Could not convert value '"+t+"' to number.")}function We(t){return new Intl.DateTimeFormat(t).formatToParts(new Date(2024,0,15)).filter(r=>r.type==="day"||r.type==="month"||r.type==="year").map(r=>r.type)}function I(t){if(!t||t==="")return;if(/^\d{4}-\d{2}-\d{2}(T|$)/.test(t)){let n=new Date(t);if(!isNaN(n.getTime()))return n}let e=t.split(/[\/.\-\s]/);if(e.length>=3&&e.every(n=>/^\d+$/.test(n))){let n=de(),o=We(n),a={};if(o.forEach((i,s)=>{a[i]=parseInt(e[s],10)}),a.year!==void 0&&a.month!==void 0&&a.day!==void 0){a.year<100&&(a.year+=2e3);let i=new Date(a.year,a.month-1,a.day);if(!isNaN(i.getTime()))return i}}let r=new Date(t);if(isNaN(r.getTime()))throw new Error("Invalid date format");return r}function fe(t){switch(t){case"boolean":return k;case"number":return V;case"Date":return I;case"string":return e=>!e||e==""?void 0:e;default:throw new Error(`Unknown data-type "${t}".`)}}function pe(t){switch(t){case"checkbox":return k;case"number":return V;case"date":case"datetime-local":return I;case"month":return e=>{let[r,n]=e.split("-").map(Number);return new Date(r,n-1)};case"week":return e=>{let[r,n]=e.split("-W").map(Number);return{year:r,week:n}};case"time":return e=>{let[r,n,o=0]=e.split(":").map(Number);return{hours:r,minutes:n,seconds:o}};default:return e=>!e||e==""?void 0:e}}function L(t,e){let r=t;if(e in r&&typeof r[e]=="boolean")return r[e];let n=t.getAttribute(e);return n===null?!1:n===""||n.toLowerCase()==="true"||n.toLowerCase()===e}var ge=Symbol("skip");function ze(t){let e=t,r=e.type||t.getAttribute("type")||"";if(r==="checkbox")return L(t,"checked");if(r==="radio")return L(t,"checked")?e.value:ge;if(r==="number")return e.value?Number(e.value):null;if(r==="date")return e.value?new Date(e.value):null;if("selectedOptions"in e&&L(t,"multiple"))return Array.from(e.selectedOptions).map(n=>n.value);if("value"in e)return e.value}function Ye(t){let e=t.getAttribute("id");if(e){let r=t.closest("form");if(r){let n=r.querySelector(`label[for="${e}"]`);if(n)return n.textContent?.trim()||null}}return null}var P=class{constructor(e,r){this.form=e;this.options=r;if(!this.form)throw new Error("Form must be specified.");this.form.addEventListener("submit",n=>{(r?.preventDefault||this.options?.submitCallback!=null)&&n.preventDefault(),this.options?.customChecks&&this.options.customChecks(e),this.validateForm()?this.options?.submitCallback?.apply(this):r?.preventDefaultOnFailed!==!1&&n.preventDefault()}),r?.autoValidate&&e.addEventListener("input",()=>{this.validateForm()})}validateForm(){let e=Array.from(this.form.querySelectorAll("input,textarea,select")),r=!0;if(this.options?.useSummary!==!0)return this.form.checkValidity()?!0:(this.form.reportValidity(),this.focusFirstErrorElement(),!1);let n=[];return e.forEach(o=>{if(!o.checkValidity()){r=!1;let a=Ye.call(this,o)||o.name||"Unnamed Field";n.push(`${a}: ${o.validationMessage}`)}}),r?this.clearErrorSummary():(this.displayErrorSummary(n),this.focusFirstErrorElement()),r}displayErrorSummary(e){this.clearErrorSummary(),this.errorSummary||this.createErrorSummary();let r=this.errorSummary.querySelector("ul");e.forEach(n=>{let o=document.createElement("li");o.textContent=n,r.appendChild(o)})}createErrorSummary(){let e=document.createElement("div");e.className="error-summary",e.style.color="red",e.setAttribute("role","alert"),e.setAttribute("aria-live","assertive"),e.setAttribute("aria-atomic","true"),this.errorSummary=e;let r=document.createElement("ul");this.errorSummary.appendChild(r),this.form.prepend(e)}addErrorToSummary(e,r){this.errorSummary||this.createErrorSummary();let n=this.errorSummary.querySelector("ul"),o=document.createElement("li");o.textContent=`${e}: ${r}`,n.appendChild(o)}clearErrorSummary(){this.errorSummary&&(this.errorSummary.querySelector("ul").innerHTML="")}focusFirstErrorElement(){let e=this.form.querySelector(":invalid");e instanceof HTMLElement&&document.activeElement!==e&&e.focus()}static FindForm(e){if(e.parentElement?.tagName=="FORM")return e.parentElement;for(let r=0;r<e.children.length;r++){let n=e.children[r];if(n.tagName=="FORM")return n}throw new Error("Parent or a direct child must be a FORM for class "+e.constructor.name)}};function Ge(t,e){t.querySelectorAll("[name]").forEach(n=>{let o=n.getAttribute("name");if(!o)return;if(o.endsWith("[]")){let i=o.slice(0,-2),s=ye(e,i);if(Array.isArray(s)){let u=n,c=u.type||n.getAttribute("type")||"";if(c==="checkbox"||c==="radio")u.checked=s.includes(u.value);else if("options"in u&&he(n,"multiple"))s.forEach(p=>{let l=Array.from(u.options).find(x=>x.value===String(p));l&&(l.selected=!0)});else if("value"in u){let p=t.querySelectorAll(`[name="${o}"]`),l=Array.from(p).indexOf(n);l>=0&&l<s.length&&(u.value=String(s[l]))}}return}let a=ye(e,o);a!=null&&Je(n,a)})}function ye(t,e){let r=[],n="",o=!1;for(let a=0;a<e.length;a++){let i=e[a];i==="["&&!o?(n&&(r.push(n),n=""),o=!0,n+=i):i==="]"&&o?(n+=i,r.push(n),n="",o=!1):i==="."&&!o?n&&(r.push(n),n=""):n+=i}return n&&r.push(n),r.reduce((a,i)=>{if(!(!a||typeof a!="object")){if(i.startsWith("[")&&i.endsWith("]")){let s=i.slice(1,-1);return a[s]}return a[i]}},t)}function Je(t,e){let r=t,n=r.type||t.getAttribute("type")||"";if(n==="checkbox")r.checked=!!e;else if(n==="radio")r.checked=r.value===String(e);else if(n==="date"&&e instanceof Date)r.value=e.toISOString().split("T")[0];else if(n==="datetime-local"&&e instanceof Date){let o=a=>String(a).padStart(2,"0");r.value=`${e.getFullYear()}-${o(e.getMonth()+1)}-${o(e.getDate())}T${o(e.getHours())}:${o(e.getMinutes())}`}else if("options"in r&&he(t,"multiple")&&Array.isArray(e)){let o=Array.from(r.options),a=e.map(String);o.forEach(i=>{i.selected=a.includes(i.value)})}else"value"in r&&(r.value=String(e))}function he(t,e){let r=t;if(e in r&&typeof r[e]=="boolean")return r[e];let n=t.getAttribute(e);return n===null?!1:n===""||n.toLowerCase()==="true"||n.toLowerCase()===e}var ve=new Map;function D(t,e=[]){return function(r){ve.set(t,{validator:r,validInputTypes:e})}}function Qe(t){return ve.get(t)}var be,q;be=[D("required")];var h=class h{static create(e){return e==="required"?new h:null}validate(e,r){e.trim()===""&&r.addError(this.getMessage())}getMessage(){return S("r-validation:required")}};q=F(null),h=C(q,0,"RequiredValidation",be,h),M(q,1,h);var U=h,Ee,j;Ee=[D("range",["number"])];var b=class b{constructor(e,r){this.min=void 0;this.max=void 0;this.min=e,this.max=r}static create(e){let r=e.match(/^range\((-?\d+(?:\.\d+)?)-(-?\d+(?:\.\d+)?)\)$/);if(r){let[,n,o]=r;return new b(parseFloat(n),parseFloat(o))}return null}validate(e,r){if(e.trim()==="")return;let n=parseFloat(e);!isNaN(n)&&n>=this.min&&n<=this.max||r.addError(this.getMessage(e))}getMessage(e){return S("r-validation:range",{min:this.min,max:this.max,actual:e})}};j=F(null),b=C(j,0,"RangeValidation",Ee,b),M(j,1,b);var W=b,xe,B;xe=[D("digits",["number"])];var E=class E{static create(e){return e==="digits"?new E:null}validate(e,r){/^\d+$/.test(e)||r.addError(this.getMessage())}getMessage(){return S("r-validation:digits")}};B=F(null),E=C(B,0,"DigitsValidation",xe,E),M(B,1,E);var z=E;export{k as BooleanConverter,I as DateConverter,z as DigitsValidation,P as FormValidator,V as NumberConverter,W as RangeValidation,D as RegisterValidator,U as RequiredValidation,fe as createConverterFromDataType,pe as createConverterFromInputType,me as getDataConverter,Qe as getValidator,Be as mapFormToClass,Ue as readData,Ge as setFormData};
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/i18n/locales/en/r-common.json", "../../src/i18n/locales/en/r-pipes.json", "../../src/i18n/locales/en/r-validation.json", "../../src/i18n/locales/sv/r-common.json", "../../src/i18n/locales/sv/r-pipes.json", "../../src/i18n/locales/sv/r-validation.json", "../../src/i18n/icu.ts", "../../src/i18n/i18n.ts", "../../src/forms/FormReader.ts", "../../src/forms/FormValidator.ts", "../../src/forms/setFormData.ts", "../../src/forms/ValidationRules.ts"],
4
+ "sourcesContent": ["{\r\n \"greeting\": \"Hello, {name}!\",\r\n \"items\": \"{count, plural, one {# item} other {# items}}\"\r\n}\r\n", "{\r\n \"today\": \"today\",\r\n \"yesterday\": \"yesterday\",\r\n \"daysAgo\": \"{count, plural, one {# day ago} other {# days ago}}\",\r\n \"pieces\": \"{count, plural, =0 {none} one {one} other {# pcs}}\"\r\n}\r\n", "{\r\n \"required\": \"This field is required.\",\r\n \"range\": \"Number must be between {min} and {max}, was {actual}.\",\r\n \"digits\": \"Please enter only digits.\"\r\n}\r\n", "{\r\n \"greeting\": \"Hej, {name}!\",\r\n \"items\": \"{count, plural, one {# sak} other {# saker}}\"\r\n}\r\n", "{\r\n \"today\": \"idag\",\r\n \"yesterday\": \"ig\u00E5r\",\r\n \"daysAgo\": \"{count, plural, one {# dag sedan} other {# dagar sedan}}\",\r\n \"pieces\": \"{count, plural, =0 {inga} one {en} other {# st}}\"\r\n}\r\n", "{\r\n \"required\": \"Detta f\u00E4lt \u00E4r obligatoriskt.\",\r\n \"range\": \"Talet m\u00E5ste vara mellan {min} och {max}, var {actual}.\",\r\n \"digits\": \"Ange endast siffror.\"\r\n}\r\n", "/**\r\n * @module icu\r\n * ICU message format support for internationalization.\r\n * Provides pluralization, select, and value interpolation.\r\n *\r\n * @example\r\n * // Simple interpolation\r\n * formatICU('Hello, {name}!', { name: 'World' });\r\n * // Returns: 'Hello, World!'\r\n *\r\n * @example\r\n * // Pluralization\r\n * formatICU('{count, plural, one {# item} other {# items}}', { count: 5 });\r\n * // Returns: '5 items'\r\n *\r\n * @example\r\n * // Select\r\n * formatICU('{gender, select, male {He} female {She} other {They}}', { gender: 'female' });\r\n * // Returns: 'She'\r\n */\r\n\r\nconst pluralRulesCache = new Map<string, Intl.PluralRules>();\r\n\r\n/**\r\n * Function type for message formatters.\r\n * Implement this to provide custom message formatting.\r\n */\r\nexport type MessageFormatter = (\r\n message: string,\r\n values?: Record<string, any>,\r\n locale?: string\r\n) => string;\r\n\r\n\r\nfunction getPluralRule(locale: string): Intl.PluralRules {\r\n if (!pluralRulesCache.has(locale)) {\r\n pluralRulesCache.set(locale, new Intl.PluralRules(locale));\r\n }\r\n return pluralRulesCache.get(locale)!;\r\n}\r\n\r\nfunction escapeRegex(s: string): string {\r\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n}\r\n\r\n/**\r\n * Default ICU message formatter implementation.\r\n * Supports simple interpolation, pluralization with exact matches, and select.\r\n *\r\n * @param message - ICU format message string\r\n * @param values - Values to interpolate\r\n * @param locale - Locale for plural rules (default: 'en')\r\n * @returns Formatted message string\r\n *\r\n * @example\r\n * defaultFormatICU('{n, plural, =0 {none} one {# item} other {# items}}', { n: 0 }, 'en');\r\n * // Returns: 'none'\r\n *\r\n * @example\r\n * defaultFormatICU('{role, select, admin {Full access} other {Limited access}}', { role: 'admin' });\r\n * // Returns: 'Full access'\r\n */\r\nexport function defaultFormatICU(\r\n message: string,\r\n values: Record<string, any>,\r\n locale: string = 'en'\r\n): string {\r\n return message.replace(\r\n /\\{(\\w+)(?:, (plural|select),((?:[^{}]*\\{[^{}]*\\})+))?\\}/g,\r\n (_, key, type, categoriesPart) => {\r\n const value = values[key];\r\n\r\n if (type === 'plural') {\r\n const exact = new RegExp(\r\n `=${escapeRegex(String(value))}\\\\s*\\\\{([^{}]*)\\\\}`\r\n ).exec(categoriesPart);\r\n if (exact) {\r\n return exact[1]\r\n .replace(`{${key}}`, String(value))\r\n .replace('#', String(value));\r\n }\r\n\r\n const rules = getPluralRule(locale);\r\n const category = rules.select(value);\r\n const match =\r\n new RegExp(`${category}\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart) ||\r\n new RegExp(`other\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart);\r\n if (match) {\r\n return match[1]\r\n .replace(`{${key}}`, String(value))\r\n .replace('#', String(value));\r\n }\r\n return String(value);\r\n }\r\n\r\n if (type === 'select') {\r\n const escaped = escapeRegex(String(value));\r\n const match =\r\n new RegExp(`\\\\b${escaped}\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart) ||\r\n new RegExp(`\\\\bother\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart);\r\n return match ? match[1] : String(value);\r\n }\r\n\r\n return value !== undefined ? String(value) : `{${key}}`;\r\n },\r\n );\r\n}\r\n\r\n/**\r\n * The active message formatter. Defaults to `defaultFormatICU`.\r\n * Can be replaced with `setMessageFormatter` for custom formatting.\r\n */\r\nexport let formatICU: MessageFormatter = defaultFormatICU;\r\n\r\n/**\r\n * Replaces the default message formatter with a custom implementation.\r\n * Use this to integrate with external i18n libraries like FormatJS.\r\n *\r\n * @param formatter - The custom formatter function\r\n *\r\n * @example\r\n * // Use FormatJS IntlMessageFormat\r\n * import { IntlMessageFormat } from 'intl-messageformat';\r\n *\r\n * setMessageFormatter((message, values, locale) => {\r\n * const fmt = new IntlMessageFormat(message, locale);\r\n * return fmt.format(values);\r\n * });\r\n */\r\nexport function setMessageFormatter(formatter: MessageFormatter) {\r\n formatICU = formatter;\r\n}", "/**\r\n * @module i18n\r\n * Internationalization support with namespace-based translations.\r\n * Uses ICU message format for pluralization, select, and formatting.\r\n *\r\n * @example\r\n * // Initialize locale\r\n * await setLocale('sv');\r\n *\r\n * // Use translations\r\n * const greeting = t('r-common:greeting', { name: 'John' });\r\n * const items = t('shop:items', { count: 5 });\r\n */\r\n\r\nimport { formatICU } from './icu';\r\n\r\ntype Locale = string;\r\ntype Namespace = string;\r\ntype TranslationMap = Record<string, string>;\r\ntype Translations = Record<Namespace, TranslationMap>;\r\n\r\nexport type MissingTranslationHandler = (\r\n key: string,\r\n namespace: string,\r\n locale: string,\r\n) => void;\r\n\r\n/**\r\n * Dispatched on `document` after `setLocale()` completes.\r\n * The `locale` property contains the new normalized locale code.\r\n *\r\n * @example\r\n * document.addEventListener('localechange', (e) => {\r\n * console.log(`Locale changed to ${e.locale}`);\r\n * this.render();\r\n * });\r\n */\r\nexport class LocaleChangeEvent extends Event {\r\n readonly locale: string;\r\n constructor(locale: string) {\r\n super('localechange', { bubbles: false });\r\n this.locale = locale;\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface DocumentEventMap {\r\n localechange: LocaleChangeEvent;\r\n }\r\n}\r\n\r\nconst fallbackLocale: Locale = 'en';\r\nlet currentLocale: Locale = fallbackLocale;\r\nconst loadedNamespaces = new Set<Namespace>();\r\nconst translations: Translations = {};\r\nlet missingHandler: MissingTranslationHandler | null = null;\r\n\r\nfunction normalizeLocale(locale: string): string {\r\n return locale.toLowerCase().split('-')[0];\r\n}\r\n\r\n/**\r\n * Sets the current locale and loads the common namespace.\r\n * Clears previously loaded translations and dispatches a `localechange` event.\r\n *\r\n * @param locale - The locale code (e.g., 'en', 'sv', 'en-US')\r\n *\r\n * @example\r\n * await setLocale('sv');\r\n */\r\nexport async function setLocale(locale: string): Promise<void> {\r\n const normalized = normalizeLocale(locale);\r\n currentLocale = normalized;\r\n loadedNamespaces.clear();\r\n Object.keys(translations).forEach(ns => delete translations[ns]);\r\n await loadNamespace('r-common');\r\n if (typeof document !== 'undefined') {\r\n document.dispatchEvent(new LocaleChangeEvent(normalized));\r\n }\r\n}\r\n\r\n/**\r\n * Loads a translation namespace on demand.\r\n * Falls back to the default locale if translations are not found.\r\n *\r\n * @param namespace - The namespace to load (e.g., 'shop', 'errors')\r\n *\r\n * @example\r\n * await loadNamespace('shop');\r\n * const price = t('shop:priceLabel');\r\n */\r\nexport async function loadNamespace(namespace: Namespace): Promise<void> {\r\n if (loadedNamespaces.has(namespace)) return;\r\n\r\n try {\r\n const module = await import(`./locales/${currentLocale}/${namespace}.json`);\r\n translations[namespace] = module.default;\r\n loadedNamespaces.add(namespace);\r\n } catch (err) {\r\n if (currentLocale !== fallbackLocale) {\r\n const fallback = await import(`./locales/${fallbackLocale}/${namespace}.json`);\r\n translations[namespace] = fallback.default;\r\n loadedNamespaces.add(namespace);\r\n } else {\r\n console.warn(`i18n: Failed to load namespace '${namespace}' for locale '${currentLocale}'`);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Loads multiple translation namespaces in parallel.\r\n *\r\n * @param namespaces - Array of namespace names to load\r\n *\r\n * @example\r\n * await loadNamespaces(['r-pipes', 'r-validation']);\r\n */\r\nexport async function loadNamespaces(namespaces: Namespace[]): Promise<void> {\r\n await Promise.all(namespaces.map(ns => loadNamespace(ns)));\r\n}\r\n\r\n/**\r\n * Translates a key with optional value interpolation.\r\n * Supports ICU message format for pluralization and select.\r\n *\r\n * @param fullKey - Translation key in format 'namespace:key' or just 'key' (uses 'r-common')\r\n * @param values - Values to interpolate into the message\r\n * @returns The translated string, or the key if not found\r\n *\r\n * @example\r\n * // Simple translation\r\n * t('greeting'); // Uses r-common:greeting\r\n *\r\n * // With namespace\r\n * t('errors:notFound');\r\n *\r\n * // With interpolation\r\n * t('welcome', { name: 'John' }); // \"Welcome, John!\"\r\n *\r\n * // With pluralization (ICU format)\r\n * t('items', { count: 5 }); // \"5 items\" or \"5 f\u00F6rem\u00E5l\"\r\n */\r\nexport function t(fullKey: string, values?: Record<string, any>): string {\r\n const [namespace, key] = fullKey.includes(':')\r\n ? fullKey.split(':')\r\n : ['r-common', fullKey];\r\n const message = translations[namespace]?.[key];\r\n if (!message) {\r\n if (missingHandler) missingHandler(key, namespace, currentLocale);\r\n return fullKey;\r\n }\r\n try {\r\n return formatICU(message, values, currentLocale) as string;\r\n } catch {\r\n return fullKey;\r\n }\r\n}\r\n\r\n/**\r\n * Returns the current locale code.\r\n *\r\n * @returns The normalized locale code (e.g., 'en', 'sv')\r\n */\r\nexport function getCurrentLocale(): string {\r\n return currentLocale;\r\n}\r\n\r\n/**\r\n * Registers a handler called when `t()` encounters a missing translation key.\r\n * Pass `null` to remove the handler.\r\n *\r\n * @param handler - Callback receiving the key, namespace, and locale\r\n *\r\n * @example\r\n * onMissingTranslation((key, ns, locale) => {\r\n * console.warn(`Missing: ${ns}:${key} [${locale}]`);\r\n * });\r\n */\r\nexport function onMissingTranslation(handler: MissingTranslationHandler | null): void {\r\n missingHandler = handler;\r\n}\r\n", "/**\r\n * @module FormReader\r\n * Utilities for reading form data into typed objects.\r\n * Handles type conversion based on input types and data-type attributes.\r\n *\r\n * @example\r\n * // Basic form reading\r\n * const form = document.querySelector('form');\r\n * const data = readData(form);\r\n *\r\n * // Type-safe mapping to a class instance\r\n * const user = mapFormToClass(form, new UserDTO());\r\n */\r\n\r\nimport { getCurrentLocale } from '../i18n/i18n';\r\n\r\n/**\r\n * Maps form field values to a class instance's properties.\r\n * Automatically converts values based on input types (checkbox, number, date).\r\n *\r\n * Form field names must match property names on the target instance.\r\n *\r\n * @template T - The type of the class instance\r\n * @param form - The HTML form element to read from\r\n * @param instance - The class instance to populate\r\n * @param options - Configuration options\r\n * @param options.throwOnMissingProperty - Throw if form field has no matching property\r\n * @param options.throwOnMissingField - Throw if class property has no matching form field\r\n * @returns The populated instance\r\n *\r\n * @example\r\n * class UserDTO {\r\n * name: string = '';\r\n * email: string = '';\r\n * age: number = 0;\r\n * newsletter: boolean = false;\r\n * }\r\n *\r\n * const form = document.querySelector('form');\r\n * const user = mapFormToClass(form, new UserDTO());\r\n * console.log(user.name, user.age, user.newsletter);\r\n *\r\n * @example\r\n * // With validation\r\n * const user = mapFormToClass(form, new UserDTO(), {\r\n * throwOnMissingProperty: true, // Catch typos in form field names\r\n * throwOnMissingField: true // Ensure all DTO fields are in form\r\n * });\r\n */\r\nexport function mapFormToClass<T extends object>(\r\n form: HTMLFormElement,\r\n instance: T,\r\n options: {\r\n throwOnMissingProperty?: boolean;\r\n throwOnMissingField?: boolean;\r\n } = {}\r\n): T {\r\n const formElements = form.querySelectorAll('input, select, textarea');\r\n\r\n formElements.forEach((element) => {\r\n if (!element.hasAttribute('name')) return;\r\n if (booleanAttr(element, 'disabled')) return;\r\n\r\n const propertyName = element.getAttribute('name')!;\r\n\r\n if (!(propertyName in instance)) {\r\n if (options.throwOnMissingProperty) {\r\n throw new Error(\r\n `Form field \"${propertyName}\" has no matching property in class instance`\r\n );\r\n }\r\n return;\r\n }\r\n\r\n const value = readElementValue(element);\r\n if (value === SKIP) return;\r\n\r\n (instance as Record<string, unknown>)[propertyName] = value;\r\n });\r\n\r\n if (options.throwOnMissingField) {\r\n const formFieldNames = new Set<string>();\r\n formElements.forEach((element) => {\r\n if (element.hasAttribute('name')) {\r\n formFieldNames.add(element.getAttribute('name')!);\r\n }\r\n });\r\n\r\n for (const prop in instance) {\r\n if (\r\n typeof instance[prop] !== 'function' &&\r\n Object.prototype.hasOwnProperty.call(instance, prop) &&\r\n !formFieldNames.has(prop)\r\n ) {\r\n throw new Error(\r\n `Class property \"${prop}\" has no matching form field`\r\n );\r\n }\r\n }\r\n }\r\n\r\n return instance;\r\n}\r\n\r\n/**\r\n * Configuration options for form reading operations.\r\n */\r\nexport interface FormReaderOptions {\r\n /** Prefix to strip from field names when mapping to properties */\r\n prefix?: string;\r\n /** If true, checkboxes return their value instead of true/false */\r\n disableBinaryCheckbox?: boolean;\r\n /** If true, radio buttons return their value instead of true/false */\r\n disableBinaryRadioButton?: boolean;\r\n}\r\n\r\n/**\r\n * Gets the appropriate type converter function for a form element.\r\n * Uses the `data-type` attribute if present, otherwise infers from input type.\r\n *\r\n * @param element - The form element to get a converter for\r\n * @returns A function that converts string values to the appropriate type\r\n *\r\n * @example\r\n * // With data-type attribute\r\n * <input name=\"age\" data-type=\"number\" />\r\n * const converter = getDataConverter(input);\r\n * converter('42'); // Returns: 42 (number)\r\n *\r\n * @example\r\n * // Inferred from input type\r\n * <input type=\"checkbox\" name=\"active\" />\r\n * const converter = getDataConverter(checkbox);\r\n * converter('true'); // Returns: true (boolean)\r\n */\r\nexport function getDataConverter(element: HTMLElement): ConverterFunc {\r\n const dataType = element.getAttribute('data-type') as DataType | null;\r\n if (dataType) {\r\n return createConverterFromDataType(dataType);\r\n }\r\n\r\n if (element instanceof HTMLInputElement) {\r\n return createConverterFromInputType(element.type as InputType);\r\n }\r\n\r\n // Handle custom form-associated elements with checked property (boolean values)\r\n if ('checked' in element && typeof (element as any).checked === 'boolean') {\r\n return BooleanConverter as ConverterFunc;\r\n }\r\n\r\n return (str) => str;\r\n}\r\n\r\n\r\n/**\r\n * Reads all form data into a plain object with automatic type conversion.\r\n * Handles multiple values (e.g., multi-select) and custom form-associated elements.\r\n *\r\n * Type conversion is based on:\r\n * 1. `data-type` attribute if present (number, boolean, string, Date)\r\n * 2. Input type (checkbox, number, date, etc.)\r\n * 3. Falls back to string\r\n *\r\n * @param form - The HTML form element to read\r\n * @returns Object with property names matching field names\r\n *\r\n * @example\r\n * // HTML form\r\n * <form>\r\n * <input name=\"username\" value=\"john\" />\r\n * <input name=\"age\" type=\"number\" value=\"25\" />\r\n * <input name=\"active\" type=\"checkbox\" checked />\r\n * <select name=\"colors\" multiple>\r\n * <option value=\"red\" selected>Red</option>\r\n * <option value=\"blue\" selected>Blue</option>\r\n * </select>\r\n * </form>\r\n *\r\n * // Reading the form\r\n * const data = readData(form);\r\n * // Returns: { username: 'john', age: 25, active: true, colors: ['red', 'blue'] }\r\n *\r\n * @example\r\n * // With custom form elements\r\n * <form>\r\n * <r-input name=\"email\" value=\"test@example.com\" />\r\n * <r-checkbox name=\"terms\" checked />\r\n * </form>\r\n * const data = readData(form);\r\n 1*/\r\nexport function readData<T = Record<string, unknown>>(form: HTMLFormElement): T{\r\n const data: Record<string, unknown> = {};\r\n const formData = new FormData(form);\r\n const seen = new Set<string>();\r\n\r\n formData.forEach((_, name) => {\r\n if (seen.has(name)) return;\r\n seen.add(name);\r\n\r\n const values = formData.getAll(name);\r\n const element = form.elements.namedItem(name);\r\n const converter = element ? getDataConverter(element as HTMLElement) : (v: string) => v;\r\n\r\n if (values.length === 1) {\r\n const v = values[0];\r\n data[name] = typeof v === 'string' ? converter(v) : v;\r\n } else {\r\n data[name] = values.map(v => typeof v === 'string' ? converter(v) : v);\r\n }\r\n });\r\n\r\n for (let i = 0; i < form.elements.length; i++) {\r\n const el = form.elements[i] as HTMLInputElement;\r\n if (el.type === 'checkbox' && el.name && !seen.has(el.name)) {\r\n seen.add(el.name);\r\n data[el.name] = false;\r\n }\r\n }\r\n\r\n return data as T;\r\n}\r\n\r\n/**\r\n * Function type for converting string form values to typed values.\r\n */\r\nexport type ConverterFunc = (value: string) => unknown;\r\n\r\n/**\r\n * Supported data-type attribute values for explicit type conversion.\r\n */\r\nexport type DataType = 'number' | 'boolean' | 'string' | 'Date';\r\n\r\n/**\r\n * Supported HTML input types for automatic type inference.\r\n */\r\nexport type InputType =\r\n | 'tel'\r\n | 'text'\r\n | 'checkbox'\r\n | 'radio'\r\n | 'number'\r\n | 'color'\r\n | 'date'\r\n | 'datetime-local'\r\n | 'month'\r\n | 'week'\r\n | 'time';\r\n\r\n/**\r\n * Converts string values to booleans.\r\n * Handles 'true'/'false' strings and numeric values (>0 is true).\r\n *\r\n * @param value - String value to convert\r\n * @returns Boolean value or undefined if empty\r\n * @throws Error if value cannot be interpreted as boolean\r\n */\r\nexport function BooleanConverter(value?: string): boolean | undefined {\r\n if (!value || value == '') {\r\n return undefined;\r\n }\r\n\r\n const lower = value.toLowerCase();\r\n\r\n if (lower === 'true' || lower === 'on' || Number(value) > 0) {\r\n return true;\r\n }\r\n\r\n if (lower === 'false' || lower === 'off' || Number(value) <= 0) {\r\n return false;\r\n }\r\n\r\n throw new Error(\"Could not convert value '\" + value + \"' to boolean.\");\r\n}\r\n\r\n/**\r\n * Converts string values to numbers.\r\n *\r\n * @param value - String value to convert\r\n * @returns Number value or undefined if empty\r\n * @throws Error if value is not a valid number\r\n */\r\nexport function NumberConverter(value?: string): number | undefined {\r\n if (!value || value == '') {\r\n return undefined;\r\n }\r\n const nr = Number(value);\r\n if (!isNaN(nr)) {\r\n return nr;\r\n }\r\n throw new Error(\"Could not convert value '\" + value + \"' to number.\");\r\n}\r\n\r\n/**\r\n * Detects the order of day/month/year parts for a given locale\r\n * using `Intl.DateTimeFormat.formatToParts`.\r\n *\r\n * @example\r\n * getLocaleDateOrder('en-US') // ['month', 'day', 'year']\r\n * getLocaleDateOrder('sv') // ['year', 'month', 'day']\r\n * getLocaleDateOrder('de') // ['day', 'month', 'year']\r\n */\r\nfunction getLocaleDateOrder(locale: string): ('day' | 'month' | 'year')[] {\r\n const parts = new Intl.DateTimeFormat(locale).formatToParts(new Date(2024, 0, 15));\r\n return parts\r\n .filter((p): p is Intl.DateTimeFormatPart & { type: 'day' | 'month' | 'year' } =>\r\n p.type === 'day' || p.type === 'month' || p.type === 'year')\r\n .map(p => p.type);\r\n}\r\n\r\n/**\r\n * Converts string values to Date objects.\r\n * Supports both ISO format (`2024-01-15`) and locale-specific formats\r\n * (`01/15/2024` for en-US, `15.01.2024` for de, etc.) based on the\r\n * current i18n locale.\r\n *\r\n * @param value - Date string in ISO or locale format\r\n * @returns Date object\r\n * @throws Error if value is not a valid date\r\n *\r\n * @example\r\n * // ISO format (from <input type=\"date\">)\r\n * DateConverter('2024-01-15') // Date(2024, 0, 15)\r\n *\r\n * // Locale format (from <input type=\"text\" data-type=\"Date\">)\r\n * // with locale set to 'sv': 2024-01-15\r\n * // with locale set to 'en-US': 01/15/2024\r\n * // with locale set to 'de': 15.01.2024\r\n */\r\nexport function DateConverter(value: string): Date | undefined {\r\n if (!value || value === '') return undefined;\r\n\r\n if (/^\\d{4}-\\d{2}-\\d{2}(T|$)/.test(value)) {\r\n const date = new Date(value);\r\n if (!isNaN(date.getTime())) return date;\r\n }\r\n\r\n const numericParts = value.split(/[\\/.\\-\\s]/);\r\n if (numericParts.length >= 3 && numericParts.every(p => /^\\d+$/.test(p))) {\r\n const locale = getCurrentLocale();\r\n const order = getLocaleDateOrder(locale);\r\n const mapped: Record<string, number> = {};\r\n order.forEach((type, i) => {\r\n mapped[type] = parseInt(numericParts[i], 10);\r\n });\r\n\r\n if (mapped.year !== undefined && mapped.month !== undefined && mapped.day !== undefined) {\r\n if (mapped.year < 100) mapped.year += 2000;\r\n const date = new Date(mapped.year, mapped.month - 1, mapped.day);\r\n if (!isNaN(date.getTime())) return date;\r\n }\r\n }\r\n\r\n const date = new Date(value);\r\n if (isNaN(date.getTime())) {\r\n throw new Error('Invalid date format');\r\n }\r\n return date;\r\n}\r\n\r\n/**\r\n * Creates a converter function based on the data-type attribute value.\r\n *\r\n * @param dataType - The data-type attribute value\r\n * @returns Appropriate converter function for the type\r\n */\r\nexport function createConverterFromDataType(dataType: DataType): ConverterFunc {\r\n switch (dataType) {\r\n case 'boolean':\r\n return BooleanConverter as ConverterFunc;\r\n case 'number':\r\n return NumberConverter as ConverterFunc;\r\n case 'Date':\r\n return DateConverter;\r\n case 'string':\r\n return (value) => (!value || value == '' ? undefined : value);\r\n default:\r\n throw new Error(`Unknown data-type \"${dataType}\".`);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a converter function based on HTML input type.\r\n * Handles special types like checkbox, date, time, week, and month.\r\n *\r\n * @param inputType - The HTML input type attribute value\r\n * @returns Appropriate converter function for the type\r\n */\r\nexport function createConverterFromInputType(inputType: InputType): ConverterFunc {\r\n switch (inputType) {\r\n case 'checkbox':\r\n return BooleanConverter as ConverterFunc;\r\n\r\n case 'number':\r\n return NumberConverter as ConverterFunc;\r\n\r\n case 'date':\r\n case 'datetime-local':\r\n return DateConverter;\r\n\r\n case 'month':\r\n return (value) => {\r\n const [year, month] = value.split('-').map(Number);\r\n return new Date(year, month - 1);\r\n };\r\n\r\n case 'week':\r\n return (value) => {\r\n const [year, week] = value.split('-W').map(Number);\r\n return { year, week };\r\n };\r\n\r\n case 'time':\r\n return (value) => {\r\n const [hours, minutes, seconds = 0] = value.split(':').map(Number);\r\n return { hours, minutes, seconds };\r\n };\r\n\r\n default:\r\n return (value) => (!value || value == '' ? undefined : value);\r\n }\r\n}\r\n\r\nfunction booleanAttr(element: Element, name: string): boolean {\r\n const el = element as Record<string, any>;\r\n if (name in el && typeof el[name] === 'boolean') return el[name];\r\n const attr = element.getAttribute(name);\r\n if (attr === null) return false;\r\n if (attr === '' || attr.toLowerCase() === 'true' || attr.toLowerCase() === name) return true;\r\n return false;\r\n}\r\n\r\nconst SKIP = Symbol('skip');\r\n\r\nfunction readElementValue(element: Element): unknown {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox') {\r\n return booleanAttr(element, 'checked');\r\n }\r\n\r\n if (type === 'radio') {\r\n if (!booleanAttr(element, 'checked')) return SKIP;\r\n return el.value;\r\n }\r\n\r\n if (type === 'number') {\r\n return el.value ? Number(el.value) : null;\r\n }\r\n\r\n if (type === 'date') {\r\n return el.value ? new Date(el.value) : null;\r\n }\r\n\r\n if ('selectedOptions' in el && booleanAttr(element, 'multiple')) {\r\n return Array.from(el.selectedOptions as NodeListOf<HTMLOptionElement>)\r\n .map((o: HTMLOptionElement) => o.value);\r\n }\r\n\r\n if ('value' in el) {\r\n return el.value;\r\n }\r\n\r\n return undefined;\r\n}", "/**\r\n * @module FormValidator\r\n * Form validation with support for native HTML5 validation and error summaries.\r\n * Provides automatic validation on submit with customizable behavior.\r\n *\r\n * @example\r\n * // Basic usage with submit callback\r\n * const form = document.querySelector('form');\r\n * const validator = new FormValidator(form, {\r\n * submitCallback: () => saveData()\r\n * });\r\n *\r\n * @example\r\n * // With auto-validation on input\r\n * const validator = new FormValidator(form, {\r\n * autoValidate: true,\r\n * useSummary: true\r\n * });\r\n */\r\n\r\n/**\r\n * Gets the human-readable field name from its associated label.\r\n */\r\nfunction getFieldName(element: HTMLElement): string | null {\r\n const id = element.getAttribute('id');\r\n if (id) {\r\n const form = element.closest('form');\r\n if (form) {\r\n const label = form.querySelector(`label[for=\"${id}\"]`) as HTMLLabelElement | null;\r\n if (label) {\r\n return label.textContent?.trim() || null;\r\n }\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Configuration options for FormValidator.\r\n */\r\nexport interface ValidatorOptions {\r\n /** Validate on every input event, not just submit */\r\n autoValidate?: boolean;\r\n /** Show errors in a summary element instead of browser tooltips */\r\n useSummary?: boolean;\r\n /** Custom validation function called before native validation */\r\n customChecks?: (form: HTMLFormElement) => void;\r\n /** Always prevent default form submission */\r\n preventDefault?: boolean;\r\n /** Prevent default on validation failure (default: true) */\r\n preventDefaultOnFailed?: boolean;\r\n /** Callback invoked when form passes validation */\r\n submitCallback?: () => void;\r\n}\r\n\r\n/**\r\n * Form validation helper that integrates with HTML5 validation.\r\n * Supports error summaries, auto-validation, and custom submit handling.\r\n *\r\n * @example\r\n * // Prevent submission and handle manually\r\n * class MyComponent extends HTMLElement {\r\n * private validator: FormValidator;\r\n *\r\n * connectedCallback() {\r\n * const form = this.querySelector('form');\r\n * this.validator = new FormValidator(form, {\r\n * submitCallback: () => this.handleSubmit()\r\n * });\r\n * }\r\n *\r\n * private async handleSubmit() {\r\n * const data = readData(this.form);\r\n * await fetch('/api/save', { method: 'POST', body: JSON.stringify(data) });\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // With error summary display\r\n * const validator = new FormValidator(form, {\r\n * useSummary: true,\r\n * autoValidate: true\r\n * });\r\n */\r\nexport class FormValidator {\r\n private errorSummary: HTMLDivElement;\r\n\r\n constructor(\r\n private form: HTMLFormElement,\r\n private options?: ValidatorOptions\r\n ) {\r\n if (!this.form) {\r\n throw new Error('Form must be specified.');\r\n }\r\n\r\n this.form.addEventListener('submit', (event) => {\r\n if (\r\n options?.preventDefault ||\r\n this.options?.submitCallback != null\r\n ) {\r\n event.preventDefault();\r\n }\r\n if (this.options?.customChecks) {\r\n this.options.customChecks(form);\r\n }\r\n\r\n if (this.validateForm()) {\r\n this.options?.submitCallback?.apply(this);\r\n } else {\r\n if (options?.preventDefaultOnFailed !== false) {\r\n event.preventDefault();\r\n }\r\n }\r\n });\r\n\r\n if (options?.autoValidate) {\r\n form.addEventListener('input', (/*e: InputEvent*/) => {\r\n this.validateForm();\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Validates all form fields.\r\n * Uses native HTML5 validation and optionally displays an error summary.\r\n *\r\n * @returns true if form is valid, false otherwise\r\n */\r\n public validateForm(): boolean {\r\n const formElements = Array.from(\r\n this.form.querySelectorAll('input,textarea,select')\r\n ) as (HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement)[];\r\n let isFormValid = true;\r\n\r\n if (this.options?.useSummary !== true) {\r\n if (this.form.checkValidity()) {\r\n return true;\r\n }\r\n\r\n this.form.reportValidity();\r\n this.focusFirstErrorElement();\r\n return false;\r\n }\r\n\r\n const errorMessages: string[] = [];\r\n\r\n formElements.forEach((element) => {\r\n if (!element.checkValidity()) {\r\n isFormValid = false;\r\n const fieldName =\r\n getFieldName.call(this, element) ||\r\n element.name ||\r\n 'Unnamed Field';\r\n errorMessages.push(\r\n `${fieldName}: ${element.validationMessage}`\r\n );\r\n }\r\n });\r\n\r\n if (!isFormValid) {\r\n this.displayErrorSummary(errorMessages);\r\n this.focusFirstErrorElement();\r\n } else {\r\n this.clearErrorSummary();\r\n }\r\n\r\n return isFormValid;\r\n }\r\n\r\n /**\r\n * Displays a list of error messages in the summary element.\r\n *\r\n * @param messages - Array of error messages to display\r\n */\r\n public displayErrorSummary(messages: string[]) {\r\n this.clearErrorSummary();\r\n if (!this.errorSummary){\r\n this.createErrorSummary();\r\n }\r\n\r\n const errorList = this.errorSummary.querySelector('ul');\r\n messages.forEach((message) => {\r\n const listItem = document.createElement('li');\r\n listItem.textContent = message;\r\n errorList.appendChild(listItem);\r\n });\r\n }\r\n\r\n private createErrorSummary() {\r\n const errorSummary = document.createElement('div');\r\n errorSummary.className = 'error-summary';\r\n errorSummary.style.color = 'red';\r\n errorSummary.setAttribute('role', 'alert');\r\n errorSummary.setAttribute('aria-live', 'assertive');\r\n errorSummary.setAttribute('aria-atomic', 'true');\r\n this.errorSummary = errorSummary;\r\n\r\n const errorList = document.createElement('ul');\r\n this.errorSummary.appendChild(errorList);\r\n\r\n this.form.prepend(errorSummary);\r\n }\r\n /**\r\n * Adds a single error to the summary display.\r\n *\r\n * @param fieldName - The name of the field with the error\r\n * @param message - The error message\r\n */\r\n public addErrorToSummary(fieldName: string, message: string) {\r\n if (!this.errorSummary){\r\n this.createErrorSummary();\r\n }\r\n const errorList = this.errorSummary.querySelector('ul');\r\n const listItem = document.createElement('li');\r\n listItem.textContent = `${fieldName}: ${message}`;\r\n errorList.appendChild(listItem);\r\n }\r\n\r\n /**\r\n * Clears all errors from the summary display.\r\n */\r\n public clearErrorSummary() {\r\n if (this.errorSummary){\r\n this.errorSummary.querySelector('ul').innerHTML='';\r\n }\r\n }\r\n\r\n private focusFirstErrorElement() {\r\n const firstInvalidElement = this.form.querySelector(':invalid');\r\n if (\r\n firstInvalidElement instanceof HTMLElement &&\r\n document.activeElement !== firstInvalidElement\r\n ) {\r\n firstInvalidElement.focus();\r\n }\r\n }\r\n\r\n /**\r\n * Finds a form element relative to the given element.\r\n * Searches parent first, then direct children.\r\n *\r\n * @param element - The element to search from\r\n * @returns The found form element\r\n * @throws Error if no form is found\r\n *\r\n * @example\r\n * class MyComponent extends HTMLElement {\r\n * connectedCallback() {\r\n * const form = FormValidator.FindForm(this);\r\n * new FormValidator(form);\r\n * }\r\n * }\r\n */\r\n public static FindForm(element: HTMLElement): HTMLFormElement {\r\n if (element.parentElement?.tagName == 'FORM') {\r\n return <HTMLFormElement>element.parentElement;\r\n } else {\r\n for (let i = 0; i < element.children.length; i++) {\r\n const child = element.children[i];\r\n if (child.tagName == 'FORM') {\r\n return <HTMLFormElement>child;\r\n }\r\n }\r\n }\r\n\r\n throw new Error(\r\n 'Parent or a direct child must be a FORM for class ' +\r\n element.constructor.name\r\n );\r\n }\r\n}\r\n", "/**\r\n * Sets form field values from a data object using the name attribute.\r\n * Supports dot notation for accessing nested properties and array handling.\r\n * \r\n * @param form - The HTML form element to populate\r\n * @param data - The data object containing values to set in the form\r\n * \r\n * @example\r\n * // Basic usage with flat object\r\n * const form = document.querySelector('form');\r\n * const data = { name: 'John', email: 'john@example.com' };\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with nested objects via dot notation\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * user: { \r\n * name: 'John', \r\n * contact: { \r\n * email: 'john@example.com' \r\n * } \r\n * } \r\n * };\r\n * // Form has fields with names like \"user.name\" and \"user.contact.email\"\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with simple arrays using [] notation\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * hobbies: ['Reading', 'Cycling', 'Cooking']\r\n * };\r\n * // Form has multiple fields with names like \"hobbies[]\"\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with array of objects using numeric indexers\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * users: [\r\n * { name: 'John', email: 'john@example.com' },\r\n * { name: 'Jane', email: 'jane@example.com' }\r\n * ]\r\n * };\r\n * // Form has fields with names like \"users[0].name\", \"users[1].email\", etc.\r\n * setFormData(form, data);\r\n */\r\nexport function setFormData(form: HTMLFormElement, data: object): void {\r\n const formElements = form.querySelectorAll('[name]');\r\n\r\n formElements.forEach(element => {\r\n\r\n const name = element.getAttribute('name');\r\n if (!name) return;\r\n\r\n // Handle simple array notation (e.g., hobbies[])\r\n if (name.endsWith('[]')) {\r\n const arrayName = name.slice(0, -2);\r\n const arrayValue = getValueByComplexPath(data, arrayName);\r\n\r\n if (Array.isArray(arrayValue)) {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox' || type === 'radio') {\r\n el.checked = arrayValue.includes(el.value);\r\n } else if ('options' in el && boolAttr(element, 'multiple')) {\r\n arrayValue.forEach(val => {\r\n const option = Array.from(el.options as HTMLOptionElement[])\r\n .find((opt: HTMLOptionElement) => opt.value === String(val));\r\n if (option) (option as HTMLOptionElement).selected = true;\r\n });\r\n } else if ('value' in el) {\r\n const allWithName = form.querySelectorAll(`[name=\"${name}\"]`);\r\n const idx = Array.from(allWithName).indexOf(element);\r\n if (idx >= 0 && idx < arrayValue.length) {\r\n el.value = String(arrayValue[idx]);\r\n }\r\n }\r\n }\r\n return;\r\n }\r\n\r\n // Handle complex paths with array indexers and dot notation\r\n const value = getValueByComplexPath(data, name);\r\n if (value === undefined || value === null) return;\r\n\r\n setElementValue(element, value);\r\n });\r\n }\r\n \r\n function getValueByComplexPath(obj: object, path: string): any {\r\n // Handle array indexers like users[0].name\r\n const segments = [];\r\n let currentSegment = '';\r\n let inBrackets = false;\r\n \r\n for (let i = 0; i < path.length; i++) {\r\n const char = path[i];\r\n \r\n if (char === '[' && !inBrackets) {\r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n }\r\n inBrackets = true;\r\n currentSegment += char;\r\n } else if (char === ']' && inBrackets) {\r\n currentSegment += char;\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n inBrackets = false;\r\n } else if (char === '.' && !inBrackets) {\r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n }\r\n } else {\r\n currentSegment += char;\r\n }\r\n }\r\n \r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n }\r\n \r\n return segments.reduce((result, segment) => {\r\n if (!result || typeof result !== 'object') return undefined;\r\n \r\n // Handle array indexer segments like [0]\r\n if (segment.startsWith('[') && segment.endsWith(']')) {\r\n const index = segment.slice(1, -1);\r\n return result[index];\r\n }\r\n \r\n return result[segment];\r\n }, obj);\r\n }\r\n \r\n function getValueByPath(obj: object, path: string): any {\r\n return path.split('.').reduce((o, key) => {\r\n return o && typeof o === 'object' ? o[key] : undefined;\r\n }, obj);\r\n }\r\n \r\n function setElementValue(element: Element, value: any): void {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox') {\r\n el.checked = Boolean(value);\r\n } else if (type === 'radio') {\r\n el.checked = el.value === String(value);\r\n } else if (type === 'date' && value instanceof Date) {\r\n el.value = value.toISOString().split('T')[0];\r\n } else if (type === 'datetime-local' && value instanceof Date) {\r\n const pad = (n: number) => String(n).padStart(2, '0');\r\n el.value = `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}T${pad(value.getHours())}:${pad(value.getMinutes())}`;\r\n } else if ('options' in el && boolAttr(element, 'multiple') && Array.isArray(value)) {\r\n const options = Array.from(el.options as HTMLOptionElement[]);\r\n const vals = value.map(String);\r\n options.forEach((opt: HTMLOptionElement) => {\r\n opt.selected = vals.includes(opt.value);\r\n });\r\n } else if ('value' in el) {\r\n el.value = String(value);\r\n }\r\n }\r\n\r\n function boolAttr(element: Element, name: string): boolean {\r\n const el = element as Record<string, any>;\r\n if (name in el && typeof el[name] === 'boolean') return el[name];\r\n const attr = element.getAttribute(name);\r\n if (attr === null) return false;\r\n if (attr === '' || attr.toLowerCase() === 'true' || attr.toLowerCase() === name) return true;\r\n return false;\r\n }", "/**\r\n * @module ValidationRules\r\n * Form validation rules for use with FormValidator.\r\n * Provides declarative validation through decorators.\r\n *\r\n * Validation messages use the i18n system. Load the 'r-validation' namespace\r\n * for localized error messages:\r\n *\r\n * @example\r\n * await loadNamespace('r-validation');\r\n *\r\n * @example\r\n * // In HTML, use validation attributes\r\n * <input name=\"age\" data-validate=\"required range(0-120)\" />\r\n */\r\n\r\nimport { t } from '../i18n/i18n';\r\n\r\n/**\r\n * Context provided to validators during validation.\r\n */\r\nexport interface ValidationContext {\r\n /** The HTML input type (text, number, email, etc.) */\r\n inputType: string;\r\n /** The data-type attribute value if present */\r\n dataType?: string;\r\n /** Adds an error message to the validation result */\r\n addError(message: string): void;\r\n}\r\n\r\n/**\r\n * Interface for custom validators.\r\n */\r\ninterface Validator {\r\n /**\r\n * Validates the given value.\r\n * @param value - The string value to validate\r\n * @param context - Validation context with type info and error reporting\r\n */\r\n validate(value: string, context: ValidationContext): void;\r\n}\r\n\r\ninterface ValidatorRegistryEntry {\r\n validator: { new (): Validator };\r\n validInputTypes: string[];\r\n}\r\n\r\nconst validators: Map<string, ValidatorRegistryEntry> = new Map();\r\n\r\n/**\r\n * Decorator to register a validator class for a specific validation name.\r\n *\r\n * @param validationName - The name used in data-validate attribute\r\n * @param validInputTypes - Optional list of input types this validator applies to\r\n *\r\n * @example\r\n * @RegisterValidator('email')\r\n * class EmailValidation implements Validator {\r\n * validate(value: string, context: ValidationContext) {\r\n * if (!value.includes('@')) {\r\n * context.addError('Invalid email address');\r\n * }\r\n * }\r\n * }\r\n */\r\nexport function RegisterValidator(validationName: string, validInputTypes: string[] = []) {\r\n return function (target: { new (...args: unknown[]): Validator }) {\r\n validators.set(validationName, { validator: target, validInputTypes });\r\n };\r\n}\r\n\r\n/**\r\n * Looks up a registered validator by name.\r\n *\r\n * @param name - The validator name used in `data-validate`\r\n * @returns The registry entry, or `undefined` if not found\r\n */\r\nexport function getValidator(name: string): ValidatorRegistryEntry | undefined {\r\n return validators.get(name);\r\n}\r\n\r\n/**\r\n * Validates that a field has a non-empty value.\r\n * Use with `data-validate=\"required\"`.\r\n */\r\n@RegisterValidator('required')\r\nexport class RequiredValidation implements Validator {\r\n static create(rule: string): RequiredValidation | null {\r\n return rule === 'required' ? new RequiredValidation() : null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (value.trim() !== ''){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage());\r\n }\r\n\r\n getMessage(): string {\r\n return t('r-validation:required');\r\n }\r\n}\r\n\r\n/**\r\n * Validates that a numeric value falls within a specified range.\r\n * Use with `data-validate=\"range(min-max)\"`.\r\n *\r\n * @example\r\n * <input name=\"age\" type=\"number\" data-validate=\"range(0-120)\" />\r\n */\r\n@RegisterValidator('range', ['number'])\r\nexport class RangeValidation implements Validator {\r\n min: number;\r\n max: number;\r\n\r\n constructor(min: number, max: number) {\r\n this.min = min;\r\n this.max = max;\r\n }\r\n\r\n static create(rule: string): RangeValidation | null {\r\n const rangeMatch = rule.match(/^range\\((-?\\d+(?:\\.\\d+)?)-(-?\\d+(?:\\.\\d+)?)\\)$/);\r\n if (rangeMatch) {\r\n const [, min, max] = rangeMatch;\r\n return new RangeValidation(parseFloat(min), parseFloat(max));\r\n }\r\n return null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (value.trim() === '') return;\r\n\r\n const num = parseFloat(value);\r\n if (!isNaN(num) && num >= this.min && num <= this.max){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage(value));\r\n }\r\n\r\n getMessage(actual: string): string {\r\n return t('r-validation:range', { min: this.min, max: this.max, actual });\r\n }\r\n}\r\n\r\n/**\r\n * Validates that a value contains only numeric digits (0-9).\r\n * Use with `data-validate=\"digits\"`.\r\n */\r\n@RegisterValidator('digits', ['number'])\r\nexport class DigitsValidation implements Validator {\r\n static create(rule: string): DigitsValidation | null {\r\n return rule === 'digits' ? new DigitsValidation() : null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (/^\\d+$/.test(value)){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage());\r\n }\r\n\r\n getMessage(): string {\r\n return t('r-validation:digits');\r\n }\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": ["require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "pluralRulesCache", "getPluralRule", "locale", "escapeRegex", "s", "defaultFormatICU", "message", "values", "_", "key", "type", "categoriesPart", "value", "exact", "category", "match", "escaped", "formatICU", "fallbackLocale", "currentLocale", "translations", "missingHandler", "t", "fullKey", "values", "namespace", "key", "message", "translations", "missingHandler", "currentLocale", "formatICU", "getCurrentLocale", "mapFormToClass", "form", "instance", "options", "formElements", "element", "booleanAttr", "propertyName", "value", "readElementValue", "SKIP", "formFieldNames", "prop", "getDataConverter", "dataType", "createConverterFromDataType", "createConverterFromInputType", "BooleanConverter", "str", "readData", "data", "formData", "seen", "_", "name", "values", "converter", "v", "i", "el", "lower", "NumberConverter", "nr", "getLocaleDateOrder", "locale", "p", "DateConverter", "date", "numericParts", "getCurrentLocale", "order", "mapped", "type", "inputType", "year", "month", "week", "hours", "minutes", "seconds", "attr", "o", "getFieldName", "element", "id", "form", "label", "FormValidator", "options", "event", "formElements", "isFormValid", "errorMessages", "fieldName", "messages", "errorList", "message", "listItem", "errorSummary", "firstInvalidElement", "i", "child", "setFormData", "form", "data", "element", "name", "arrayName", "arrayValue", "getValueByComplexPath", "el", "type", "boolAttr", "val", "option", "opt", "allWithName", "idx", "value", "setElementValue", "obj", "path", "segments", "currentSegment", "inBrackets", "i", "char", "result", "segment", "index", "setElementValue", "element", "value", "el", "type", "pad", "n", "boolAttr", "options", "vals", "opt", "name", "attr", "validators", "RegisterValidator", "validationName", "validInputTypes", "target", "getValidator", "name", "_RequiredValidation_decorators", "_init", "_RequiredValidation", "rule", "value", "context", "t", "__decoratorStart", "__decorateElement", "__runInitializers", "RequiredValidation", "_RangeValidation_decorators", "_RangeValidation", "min", "max", "rangeMatch", "num", "actual", "RangeValidation", "_DigitsValidation_decorators", "_DigitsValidation", "DigitsValidation"]
7
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Sets form field values from a data object using the name attribute.
3
+ * Supports dot notation for accessing nested properties and array handling.
4
+ *
5
+ * @param form - The HTML form element to populate
6
+ * @param data - The data object containing values to set in the form
7
+ *
8
+ * @example
9
+ * // Basic usage with flat object
10
+ * const form = document.querySelector('form');
11
+ * const data = { name: 'John', email: 'john@example.com' };
12
+ * setFormData(form, data);
13
+ *
14
+ * @example
15
+ * // Using with nested objects via dot notation
16
+ * const form = document.querySelector('form');
17
+ * const data = {
18
+ * user: {
19
+ * name: 'John',
20
+ * contact: {
21
+ * email: 'john@example.com'
22
+ * }
23
+ * }
24
+ * };
25
+ * // Form has fields with names like "user.name" and "user.contact.email"
26
+ * setFormData(form, data);
27
+ *
28
+ * @example
29
+ * // Using with simple arrays using [] notation
30
+ * const form = document.querySelector('form');
31
+ * const data = {
32
+ * hobbies: ['Reading', 'Cycling', 'Cooking']
33
+ * };
34
+ * // Form has multiple fields with names like "hobbies[]"
35
+ * setFormData(form, data);
36
+ *
37
+ * @example
38
+ * // Using with array of objects using numeric indexers
39
+ * const form = document.querySelector('form');
40
+ * const data = {
41
+ * users: [
42
+ * { name: 'John', email: 'john@example.com' },
43
+ * { name: 'Jane', email: 'jane@example.com' }
44
+ * ]
45
+ * };
46
+ * // Form has fields with names like "users[0].name", "users[1].email", etc.
47
+ * setFormData(form, data);
48
+ */
49
+ export declare function setFormData(form: HTMLFormElement, data: object): void;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Finds the closest parent element of a specific Web Component type.
3
+ * Traverses up the DOM tree looking for an ancestor matching the constructor.
4
+ *
5
+ * Useful for child components that need to communicate with or access
6
+ * their parent container component, common in composite component patterns.
7
+ *
8
+ * @template T - The type of HTMLElement to find
9
+ * @param node - The starting node to search from
10
+ * @param constructor - The class constructor of the desired element type
11
+ * @returns The matching parent element or null if not found
12
+ *
13
+ * @example
14
+ * // Inside a child component, find the parent container
15
+ * class ListItem extends HTMLElement {
16
+ * connectedCallback() {
17
+ * const list = getParentComponent(this, ListContainer);
18
+ * if (list) {
19
+ * list.registerItem(this);
20
+ * }
21
+ * }
22
+ * }
23
+ *
24
+ * @example
25
+ * // Access parent component's methods
26
+ * class TabPanel extends HTMLElement {
27
+ * activate() {
28
+ * const tabs = getParentComponent(this, TabContainer);
29
+ * tabs?.selectPanel(this);
30
+ * }
31
+ * }
32
+ *
33
+ * @example
34
+ * // Handle case where parent might not exist
35
+ * const form = getParentComponent(input, FormContainer);
36
+ * if (!form) {
37
+ * console.warn('Input must be inside a FormContainer');
38
+ * return;
39
+ * }
40
+ */
41
+ export declare function getParentComponent<T extends HTMLElement>(node: Node, constructor: {
42
+ new (...args: any[]): T;
43
+ }): T | null;
@@ -0,0 +1,44 @@
1
+ export declare class TableRenderer {
2
+ private table;
3
+ private template;
4
+ private component;
5
+ private dataMap;
6
+ private rowMap;
7
+ IdColumn: string;
8
+ constructor(table: HTMLTableElement, template: HTMLTemplateElement, idColumn: string, component: HTMLElement);
9
+ render(data: Record<string, any>[]): void;
10
+ private clearRows;
11
+ private renderRow;
12
+ private populateRow;
13
+ private attachEventHandlers;
14
+ update(data: Record<string, any>): void;
15
+ }
16
+ export declare class SortChangeEvent extends CustomEvent<SortColumn[]> {
17
+ constructor(sortColumns: SortColumn[]);
18
+ }
19
+ type SortDirection = 'asc' | 'desc';
20
+ export type SortColumn = {
21
+ column: string;
22
+ direction: SortDirection;
23
+ };
24
+ export declare class TableSorter {
25
+ private table;
26
+ private sortColumns;
27
+ private component;
28
+ constructor(table: HTMLTableElement, component: HTMLElement);
29
+ private setupListeners;
30
+ private toggle;
31
+ private emit;
32
+ private updateSortIndicators;
33
+ getSortColumns(): SortColumn[];
34
+ clear(): void;
35
+ }
36
+ declare global {
37
+ interface HTMLTableElementEventMap extends HTMLElementEventMap {
38
+ 'sortchange': SortChangeEvent;
39
+ }
40
+ interface HTMLTableElement {
41
+ addEventListener<K extends keyof HTMLTableElementEventMap>(type: K, listener: (this: HTMLTableElement, ev: HTMLTableElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
42
+ }
43
+ }
44
+ export {};
@@ -0,0 +1,9 @@
1
+ export declare class Template {
2
+ private readonly template;
3
+ private readonly bindings;
4
+ constructor(html: string);
5
+ render(data: Record<string, any>): HTMLElement;
6
+ private collectBindings;
7
+ private getNodeAtPath;
8
+ private resolveVariable;
9
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @module html
3
+ * HTML template engine with update capabilities.
4
+ * Creates templates that can be re-rendered with new data without recreating DOM nodes.
5
+ */
6
+ /**
7
+ * Result of rendering a template.
8
+ * Provides the DOM fragment and an update function for re-rendering.
9
+ */
10
+ export interface RenderTemplate {
11
+ /** The rendered DOM fragment */
12
+ fragment: DocumentFragment;
13
+ /** Updates the DOM with new data without recreating elements */
14
+ update(context: any): void;
15
+ }
16
+ /**
17
+ * Creates an updateable HTML template using tagged template literals.
18
+ * Returns an object with the fragment and an update method for efficient re-rendering.
19
+ *
20
+ * Supports:
21
+ * - Template literal substitutions (`${}`)
22
+ * - Mustache-style bindings (`{{property}}`)
23
+ * - Pipe transformations (`{{value|uppercase}}`)
24
+ * - Event handler binding
25
+ *
26
+ * @param templateStrings - The static parts of the template literal
27
+ * @param substitutions - The dynamic values interpolated into the template
28
+ * @returns A function that takes context and returns a RenderTemplate
29
+ *
30
+ * @example
31
+ * // Create and render a template
32
+ * const template = html`
33
+ * <div class="user">
34
+ * <h2>{{name}}</h2>
35
+ * <p>{{email}}</p>
36
+ * <span>{{createdAt|daysAgo}}</span>
37
+ * </div>
38
+ * `;
39
+ *
40
+ * const result = template({ name: 'John', email: 'john@example.com', createdAt: new Date() });
41
+ * container.appendChild(result.fragment);
42
+ *
43
+ * // Later, update with new data
44
+ * result.update({ name: 'Jane', email: 'jane@example.com', createdAt: new Date() });
45
+ *
46
+ * @example
47
+ * // With event handlers
48
+ * const row = html`
49
+ * <tr>
50
+ * <td>{{name}}</td>
51
+ * <td><button onclick=${function() { this.edit(this.id) }}>Edit</button></td>
52
+ * </tr>
53
+ * `;
54
+ */
55
+ export declare function html(templateStrings: TemplateStringsArray, ...substitutions: any[]): (context: any) => RenderTemplate;
@@ -0,0 +1,5 @@
1
+ export { html, RenderTemplate } from './html';
2
+ export { compileTemplate, EngineConfig, CompiledTemplate } from './template';
3
+ export * from '../templates/NodeTemplate';
4
+ export { TableRenderer, TableSorter, SortChangeEvent } from './TableRenderer';
5
+ export type { SortColumn } from './TableRenderer';