@dynamicforms/vuetify-inputs 0.11.7 → 0.13.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.
- package/dist/dynamicforms-vuetify-inputs.css +1 -1
- package/dist/dynamicforms-vuetify-inputs.js +1527 -1122
- package/dist/dynamicforms-vuetify-inputs.js.map +1 -1
- package/dist/dynamicforms-vuetify-inputs.umd.cjs +1 -1
- package/dist/dynamicforms-vuetify-inputs.umd.cjs.map +1 -1
- package/dist/index.d.ts +377 -364
- package/package.json +6 -7
- package/readme.md +17 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamicforms-vuetify-inputs.js","names":["$slots","$slots"],"sources":["../node_modules/date-fns/locale/sl/_lib/formatDistance.js","../node_modules/date-fns/locale/_lib/buildFormatLongFn.js","../node_modules/date-fns/locale/sl/_lib/formatLong.js","../node_modules/date-fns/locale/sl/_lib/formatRelative.js","../node_modules/date-fns/locale/_lib/buildLocalizeFn.js","../node_modules/date-fns/locale/sl/_lib/localize.js","../node_modules/date-fns/locale/_lib/buildMatchFn.js","../node_modules/date-fns/locale/_lib/buildMatchPatternFn.js","../node_modules/date-fns/locale/sl/_lib/match.js","../node_modules/date-fns/locale/sl.js","../src/helpers/date-time-locale.ts","../src/helpers/df-file.interface.ts","../src/helpers/df-input-hint.vue","../src/helpers/df-input-hint.vue","../src/helpers/df-label.vue","../src/helpers/df-label.vue","../src/helpers/settings.ts","../src/helpers/input-base.ts","../src/helpers/input-base.vue","../src/helpers/input-base.vue","../src/helpers/translations.ts","../src/helpers/action/action-display-style.ts","../src/helpers/action/responsive-render-options.ts","../src/helpers/action/action-render-options.ts","../src/helpers/action/action.ts","../src/helpers/use-file-touch-keepalive.ts","../src/df-actions.vue","../src/df-actions.vue","../src/df-checkbox.vue","../src/df-checkbox.vue","../src/df-color.vue","../src/df-color.vue","../src/df-datetime.vue","../src/df-datetime.vue","../src/df-file.vue","../src/df-file.vue","../src/df-image.vue","../src/df-image.vue","../src/df-input.vue","../src/df-input.vue","../src/helpers/rtf-editor/block-styles.ts","../src/helpers/rtf-editor/image-paste.ts","../src/helpers/rtf-editor/link-with-download.ts","../src/helpers/rtf-editor/media-embed.ts","../src/helpers/rtf-editor/use-editor-tick.ts","../src/helpers/rtf-editor/rtf-toolbar.vue","../src/helpers/rtf-editor/rtf-toolbar.vue","../src/helpers/rtf-editor/word-paste.ts","../src/helpers/rtf-editor/editor-core.vue","../src/helpers/rtf-editor/editor-core.vue","../src/df-rtf-editor.vue","../src/df-rtf-editor.vue","../src/helpers/df-select.helper.ts","../src/df-select.vue","../src/df-select.vue","../src/df-text-area.vue","../src/df-text-area.vue","../src/dynamicforms-components.ts","../src/vuetify-components.ts","../src/dynamicforms-components-by-tag.ts","../src/dynamicforms-component-props.ts","../src/index.ts"],"sourcesContent":["function isPluralType(val) {\n return val.one !== undefined;\n}\n\nconst formatDistanceLocale = {\n lessThanXSeconds: {\n present: {\n one: \"manj kot {{count}} sekunda\",\n two: \"manj kot {{count}} sekundi\",\n few: \"manj kot {{count}} sekunde\",\n other: \"manj kot {{count}} sekund\",\n },\n past: {\n one: \"manj kot {{count}} sekundo\",\n two: \"manj kot {{count}} sekundama\",\n few: \"manj kot {{count}} sekundami\",\n other: \"manj kot {{count}} sekundami\",\n },\n future: {\n one: \"manj kot {{count}} sekundo\",\n two: \"manj kot {{count}} sekundi\",\n few: \"manj kot {{count}} sekunde\",\n other: \"manj kot {{count}} sekund\",\n },\n },\n\n xSeconds: {\n present: {\n one: \"{{count}} sekunda\",\n two: \"{{count}} sekundi\",\n few: \"{{count}} sekunde\",\n other: \"{{count}} sekund\",\n },\n past: {\n one: \"{{count}} sekundo\",\n two: \"{{count}} sekundama\",\n few: \"{{count}} sekundami\",\n other: \"{{count}} sekundami\",\n },\n future: {\n one: \"{{count}} sekundo\",\n two: \"{{count}} sekundi\",\n few: \"{{count}} sekunde\",\n other: \"{{count}} sekund\",\n },\n },\n\n halfAMinute: \"pol minute\",\n\n lessThanXMinutes: {\n present: {\n one: \"manj kot {{count}} minuta\",\n two: \"manj kot {{count}} minuti\",\n few: \"manj kot {{count}} minute\",\n other: \"manj kot {{count}} minut\",\n },\n past: {\n one: \"manj kot {{count}} minuto\",\n two: \"manj kot {{count}} minutama\",\n few: \"manj kot {{count}} minutami\",\n other: \"manj kot {{count}} minutami\",\n },\n future: {\n one: \"manj kot {{count}} minuto\",\n two: \"manj kot {{count}} minuti\",\n few: \"manj kot {{count}} minute\",\n other: \"manj kot {{count}} minut\",\n },\n },\n\n xMinutes: {\n present: {\n one: \"{{count}} minuta\",\n two: \"{{count}} minuti\",\n few: \"{{count}} minute\",\n other: \"{{count}} minut\",\n },\n past: {\n one: \"{{count}} minuto\",\n two: \"{{count}} minutama\",\n few: \"{{count}} minutami\",\n other: \"{{count}} minutami\",\n },\n future: {\n one: \"{{count}} minuto\",\n two: \"{{count}} minuti\",\n few: \"{{count}} minute\",\n other: \"{{count}} minut\",\n },\n },\n\n aboutXHours: {\n present: {\n one: \"približno {{count}} ura\",\n two: \"približno {{count}} uri\",\n few: \"približno {{count}} ure\",\n other: \"približno {{count}} ur\",\n },\n past: {\n one: \"približno {{count}} uro\",\n two: \"približno {{count}} urama\",\n few: \"približno {{count}} urami\",\n other: \"približno {{count}} urami\",\n },\n future: {\n one: \"približno {{count}} uro\",\n two: \"približno {{count}} uri\",\n few: \"približno {{count}} ure\",\n other: \"približno {{count}} ur\",\n },\n },\n\n xHours: {\n present: {\n one: \"{{count}} ura\",\n two: \"{{count}} uri\",\n few: \"{{count}} ure\",\n other: \"{{count}} ur\",\n },\n past: {\n one: \"{{count}} uro\",\n two: \"{{count}} urama\",\n few: \"{{count}} urami\",\n other: \"{{count}} urami\",\n },\n future: {\n one: \"{{count}} uro\",\n two: \"{{count}} uri\",\n few: \"{{count}} ure\",\n other: \"{{count}} ur\",\n },\n },\n\n xDays: {\n present: {\n one: \"{{count}} dan\",\n two: \"{{count}} dni\",\n few: \"{{count}} dni\",\n other: \"{{count}} dni\",\n },\n past: {\n one: \"{{count}} dnem\",\n two: \"{{count}} dnevoma\",\n few: \"{{count}} dnevi\",\n other: \"{{count}} dnevi\",\n },\n future: {\n one: \"{{count}} dan\",\n two: \"{{count}} dni\",\n few: \"{{count}} dni\",\n other: \"{{count}} dni\",\n },\n },\n\n // no tenses for weeks?\n aboutXWeeks: {\n one: \"približno {{count}} teden\",\n two: \"približno {{count}} tedna\",\n few: \"približno {{count}} tedne\",\n other: \"približno {{count}} tednov\",\n },\n\n // no tenses for weeks?\n xWeeks: {\n one: \"{{count}} teden\",\n two: \"{{count}} tedna\",\n few: \"{{count}} tedne\",\n other: \"{{count}} tednov\",\n },\n\n aboutXMonths: {\n present: {\n one: \"približno {{count}} mesec\",\n two: \"približno {{count}} meseca\",\n few: \"približno {{count}} mesece\",\n other: \"približno {{count}} mesecev\",\n },\n past: {\n one: \"približno {{count}} mesecem\",\n two: \"približno {{count}} mesecema\",\n few: \"približno {{count}} meseci\",\n other: \"približno {{count}} meseci\",\n },\n future: {\n one: \"približno {{count}} mesec\",\n two: \"približno {{count}} meseca\",\n few: \"približno {{count}} mesece\",\n other: \"približno {{count}} mesecev\",\n },\n },\n\n xMonths: {\n present: {\n one: \"{{count}} mesec\",\n two: \"{{count}} meseca\",\n few: \"{{count}} meseci\",\n other: \"{{count}} mesecev\",\n },\n past: {\n one: \"{{count}} mesecem\",\n two: \"{{count}} mesecema\",\n few: \"{{count}} meseci\",\n other: \"{{count}} meseci\",\n },\n future: {\n one: \"{{count}} mesec\",\n two: \"{{count}} meseca\",\n few: \"{{count}} mesece\",\n other: \"{{count}} mesecev\",\n },\n },\n\n aboutXYears: {\n present: {\n one: \"približno {{count}} leto\",\n two: \"približno {{count}} leti\",\n few: \"približno {{count}} leta\",\n other: \"približno {{count}} let\",\n },\n past: {\n one: \"približno {{count}} letom\",\n two: \"približno {{count}} letoma\",\n few: \"približno {{count}} leti\",\n other: \"približno {{count}} leti\",\n },\n future: {\n one: \"približno {{count}} leto\",\n two: \"približno {{count}} leti\",\n few: \"približno {{count}} leta\",\n other: \"približno {{count}} let\",\n },\n },\n\n xYears: {\n present: {\n one: \"{{count}} leto\",\n two: \"{{count}} leti\",\n few: \"{{count}} leta\",\n other: \"{{count}} let\",\n },\n past: {\n one: \"{{count}} letom\",\n two: \"{{count}} letoma\",\n few: \"{{count}} leti\",\n other: \"{{count}} leti\",\n },\n future: {\n one: \"{{count}} leto\",\n two: \"{{count}} leti\",\n few: \"{{count}} leta\",\n other: \"{{count}} let\",\n },\n },\n\n overXYears: {\n present: {\n one: \"več kot {{count}} leto\",\n two: \"več kot {{count}} leti\",\n few: \"več kot {{count}} leta\",\n other: \"več kot {{count}} let\",\n },\n past: {\n one: \"več kot {{count}} letom\",\n two: \"več kot {{count}} letoma\",\n few: \"več kot {{count}} leti\",\n other: \"več kot {{count}} leti\",\n },\n future: {\n one: \"več kot {{count}} leto\",\n two: \"več kot {{count}} leti\",\n few: \"več kot {{count}} leta\",\n other: \"več kot {{count}} let\",\n },\n },\n\n almostXYears: {\n present: {\n one: \"skoraj {{count}} leto\",\n two: \"skoraj {{count}} leti\",\n few: \"skoraj {{count}} leta\",\n other: \"skoraj {{count}} let\",\n },\n past: {\n one: \"skoraj {{count}} letom\",\n two: \"skoraj {{count}} letoma\",\n few: \"skoraj {{count}} leti\",\n other: \"skoraj {{count}} leti\",\n },\n future: {\n one: \"skoraj {{count}} leto\",\n two: \"skoraj {{count}} leti\",\n few: \"skoraj {{count}} leta\",\n other: \"skoraj {{count}} let\",\n },\n },\n};\n\nfunction getFormFromCount(count) {\n switch (count % 100) {\n case 1:\n return \"one\";\n case 2:\n return \"two\";\n case 3:\n case 4:\n return \"few\";\n default:\n return \"other\";\n }\n}\n\nexport const formatDistance = (token, count, options) => {\n let result = \"\";\n let tense = \"present\";\n\n if (options?.addSuffix) {\n if (options.comparison && options.comparison > 0) {\n tense = \"future\";\n result = \"čez \";\n } else {\n tense = \"past\";\n result = \"pred \";\n }\n }\n\n const tokenValue = formatDistanceLocale[token];\n\n if (typeof tokenValue === \"string\") {\n result += tokenValue;\n } else {\n const form = getFormFromCount(count);\n if (isPluralType(tokenValue)) {\n result += tokenValue[form].replace(\"{{count}}\", String(count));\n } else {\n result += tokenValue[tense][form].replace(\"{{count}}\", String(count));\n }\n }\n\n return result;\n};\n","export function buildFormatLongFn(args) {\n return (options = {}) => {\n // TODO: Remove String()\n const width = options.width ? String(options.width) : args.defaultWidth;\n const format = args.formats[width] || args.formats[args.defaultWidth];\n return format;\n };\n}\n","import { buildFormatLongFn } from \"../../_lib/buildFormatLongFn.js\";\n\nconst dateFormats = {\n full: \"EEEE, dd. MMMM y\",\n long: \"dd. MMMM y\",\n medium: \"d. MMM y\",\n short: \"d. MM. yy\",\n};\n\nconst timeFormats = {\n full: \"HH:mm:ss zzzz\",\n long: \"HH:mm:ss z\",\n medium: \"HH:mm:ss\",\n short: \"HH:mm\",\n};\n\nconst dateTimeFormats = {\n full: \"{{date}} {{time}}\",\n long: \"{{date}} {{time}}\",\n medium: \"{{date}} {{time}}\",\n short: \"{{date}} {{time}}\",\n};\n\nexport const formatLong = {\n date: buildFormatLongFn({\n formats: dateFormats,\n defaultWidth: \"full\",\n }),\n\n time: buildFormatLongFn({\n formats: timeFormats,\n defaultWidth: \"full\",\n }),\n\n dateTime: buildFormatLongFn({\n formats: dateTimeFormats,\n defaultWidth: \"full\",\n }),\n};\n","const formatRelativeLocale = {\n lastWeek: (date) => {\n const day = date.getDay();\n\n switch (day) {\n case 0:\n return \"'prejšnjo nedeljo ob' p\";\n case 3:\n return \"'prejšnjo sredo ob' p\";\n case 6:\n return \"'prejšnjo soboto ob' p\";\n default:\n return \"'prejšnji' EEEE 'ob' p\";\n }\n },\n yesterday: \"'včeraj ob' p\",\n today: \"'danes ob' p\",\n tomorrow: \"'jutri ob' p\",\n nextWeek: (date) => {\n const day = date.getDay();\n\n switch (day) {\n case 0:\n return \"'naslednjo nedeljo ob' p\";\n case 3:\n return \"'naslednjo sredo ob' p\";\n case 6:\n return \"'naslednjo soboto ob' p\";\n default:\n return \"'naslednji' EEEE 'ob' p\";\n }\n },\n other: \"P\",\n};\n\nexport const formatRelative = (token, date, _baseDate, _options) => {\n const format = formatRelativeLocale[token];\n\n if (typeof format === \"function\") {\n return format(date);\n }\n\n return format;\n};\n","/**\n * The localize function argument callback which allows to convert raw value to\n * the actual type.\n *\n * @param value - The value to convert\n *\n * @returns The converted value\n */\n\n/**\n * The map of localized values for each width.\n */\n\n/**\n * The index type of the locale unit value. It types conversion of units of\n * values that don't start at 0 (i.e. quarters).\n */\n\n/**\n * Converts the unit value to the tuple of values.\n */\n\n/**\n * The tuple of localized era values. The first element represents BC,\n * the second element represents AD.\n */\n\n/**\n * The tuple of localized quarter values. The first element represents Q1.\n */\n\n/**\n * The tuple of localized day values. The first element represents Sunday.\n */\n\n/**\n * The tuple of localized month values. The first element represents January.\n */\n\nexport function buildLocalizeFn(args) {\n return (value, options) => {\n const context = options?.context ? String(options.context) : \"standalone\";\n\n let valuesArray;\n if (context === \"formatting\" && args.formattingValues) {\n const defaultWidth = args.defaultFormattingWidth || args.defaultWidth;\n const width = options?.width ? String(options.width) : defaultWidth;\n\n valuesArray =\n args.formattingValues[width] || args.formattingValues[defaultWidth];\n } else {\n const defaultWidth = args.defaultWidth;\n const width = options?.width ? String(options.width) : args.defaultWidth;\n\n valuesArray = args.values[width] || args.values[defaultWidth];\n }\n const index = args.argumentCallback ? args.argumentCallback(value) : value;\n\n // @ts-expect-error - For some reason TypeScript just don't want to match it, no matter how hard we try. I challenge you to try to remove it!\n return valuesArray[index];\n };\n}\n","import { buildLocalizeFn } from \"../../_lib/buildLocalizeFn.js\";\n\nconst eraValues = {\n narrow: [\"pr. n. št.\", \"po n. št.\"],\n abbreviated: [\"pr. n. št.\", \"po n. št.\"],\n wide: [\"pred našim štetjem\", \"po našem štetju\"],\n};\n\nconst quarterValues = {\n narrow: [\"1\", \"2\", \"3\", \"4\"],\n abbreviated: [\"1. čet.\", \"2. čet.\", \"3. čet.\", \"4. čet.\"],\n wide: [\"1. četrtletje\", \"2. četrtletje\", \"3. četrtletje\", \"4. četrtletje\"],\n};\n\nconst monthValues = {\n narrow: [\"j\", \"f\", \"m\", \"a\", \"m\", \"j\", \"j\", \"a\", \"s\", \"o\", \"n\", \"d\"],\n abbreviated: [\n \"jan.\",\n \"feb.\",\n \"mar.\",\n \"apr.\",\n \"maj\",\n \"jun.\",\n \"jul.\",\n \"avg.\",\n \"sep.\",\n \"okt.\",\n \"nov.\",\n \"dec.\",\n ],\n\n wide: [\n \"januar\",\n \"februar\",\n \"marec\",\n \"april\",\n \"maj\",\n \"junij\",\n \"julij\",\n \"avgust\",\n \"september\",\n \"oktober\",\n \"november\",\n \"december\",\n ],\n};\n\nconst dayValues = {\n narrow: [\"n\", \"p\", \"t\", \"s\", \"č\", \"p\", \"s\"],\n short: [\"ned.\", \"pon.\", \"tor.\", \"sre.\", \"čet.\", \"pet.\", \"sob.\"],\n abbreviated: [\"ned.\", \"pon.\", \"tor.\", \"sre.\", \"čet.\", \"pet.\", \"sob.\"],\n\n wide: [\n \"nedelja\",\n \"ponedeljek\",\n \"torek\",\n \"sreda\",\n \"četrtek\",\n \"petek\",\n \"sobota\",\n ],\n};\n\nconst dayPeriodValues = {\n narrow: {\n am: \"d\",\n pm: \"p\",\n midnight: \"24.00\",\n noon: \"12.00\",\n morning: \"j\",\n afternoon: \"p\",\n evening: \"v\",\n night: \"n\",\n },\n abbreviated: {\n am: \"dop.\",\n pm: \"pop.\",\n midnight: \"poln.\",\n noon: \"pold.\",\n morning: \"jut.\",\n afternoon: \"pop.\",\n evening: \"več.\",\n night: \"noč\",\n },\n wide: {\n am: \"dop.\",\n pm: \"pop.\",\n midnight: \"polnoč\",\n noon: \"poldne\",\n morning: \"jutro\",\n afternoon: \"popoldne\",\n evening: \"večer\",\n night: \"noč\",\n },\n};\n\nconst formattingDayPeriodValues = {\n narrow: {\n am: \"d\",\n pm: \"p\",\n midnight: \"24.00\",\n noon: \"12.00\",\n morning: \"zj\",\n afternoon: \"p\",\n evening: \"zv\",\n night: \"po\",\n },\n abbreviated: {\n am: \"dop.\",\n pm: \"pop.\",\n midnight: \"opoln.\",\n noon: \"opold.\",\n morning: \"zjut.\",\n afternoon: \"pop.\",\n evening: \"zveč.\",\n night: \"ponoči\",\n },\n wide: {\n am: \"dop.\",\n pm: \"pop.\",\n midnight: \"opolnoči\",\n noon: \"opoldne\",\n morning: \"zjutraj\",\n afternoon: \"popoldan\",\n evening: \"zvečer\",\n night: \"ponoči\",\n },\n};\n\nconst ordinalNumber = (dirtyNumber, _options) => {\n const number = Number(dirtyNumber);\n return number + \".\";\n};\n\nexport const localize = {\n ordinalNumber,\n\n era: buildLocalizeFn({\n values: eraValues,\n defaultWidth: \"wide\",\n }),\n\n quarter: buildLocalizeFn({\n values: quarterValues,\n defaultWidth: \"wide\",\n argumentCallback: (quarter) => quarter - 1,\n }),\n\n month: buildLocalizeFn({\n values: monthValues,\n defaultWidth: \"wide\",\n }),\n\n day: buildLocalizeFn({\n values: dayValues,\n defaultWidth: \"wide\",\n }),\n\n dayPeriod: buildLocalizeFn({\n values: dayPeriodValues,\n defaultWidth: \"wide\",\n formattingValues: formattingDayPeriodValues,\n defaultFormattingWidth: \"wide\",\n }),\n};\n","export function buildMatchFn(args) {\n return (string, options = {}) => {\n const width = options.width;\n\n const matchPattern =\n (width && args.matchPatterns[width]) ||\n args.matchPatterns[args.defaultMatchWidth];\n const matchResult = string.match(matchPattern);\n\n if (!matchResult) {\n return null;\n }\n const matchedString = matchResult[0];\n\n const parsePatterns =\n (width && args.parsePatterns[width]) ||\n args.parsePatterns[args.defaultParseWidth];\n\n const key = Array.isArray(parsePatterns)\n ? findIndex(parsePatterns, (pattern) => pattern.test(matchedString))\n : // [TODO] -- I challenge you to fix the type\n findKey(parsePatterns, (pattern) => pattern.test(matchedString));\n\n let value;\n\n value = args.valueCallback ? args.valueCallback(key) : key;\n value = options.valueCallback\n ? // [TODO] -- I challenge you to fix the type\n options.valueCallback(value)\n : value;\n\n const rest = string.slice(matchedString.length);\n\n return { value, rest };\n };\n}\n\nfunction findKey(object, predicate) {\n for (const key in object) {\n if (\n Object.prototype.hasOwnProperty.call(object, key) &&\n predicate(object[key])\n ) {\n return key;\n }\n }\n return undefined;\n}\n\nfunction findIndex(array, predicate) {\n for (let key = 0; key < array.length; key++) {\n if (predicate(array[key])) {\n return key;\n }\n }\n return undefined;\n}\n","export function buildMatchPatternFn(args) {\n return (string, options = {}) => {\n const matchResult = string.match(args.matchPattern);\n if (!matchResult) return null;\n const matchedString = matchResult[0];\n\n const parseResult = string.match(args.parsePattern);\n if (!parseResult) return null;\n let value = args.valueCallback\n ? args.valueCallback(parseResult[0])\n : parseResult[0];\n\n // [TODO] I challenge you to fix the type\n value = options.valueCallback ? options.valueCallback(value) : value;\n\n const rest = string.slice(matchedString.length);\n\n return { value, rest };\n };\n}\n","import { buildMatchFn } from \"../../_lib/buildMatchFn.js\";\nimport { buildMatchPatternFn } from \"../../_lib/buildMatchPatternFn.js\";\n\nconst matchOrdinalNumberPattern = /^(\\d+)\\./i;\nconst parseOrdinalNumberPattern = /\\d+/i;\n\nconst matchEraPatterns = {\n abbreviated: /^(pr\\. n\\. št\\.|po n\\. št\\.)/i,\n wide: /^(pred Kristusom|pred na[sš]im [sš]tetjem|po Kristusu|po na[sš]em [sš]tetju|na[sš]ega [sš]tetja)/i,\n};\nconst parseEraPatterns = {\n any: [/^pr/i, /^(po|na[sš]em)/i],\n};\n\nconst matchQuarterPatterns = {\n narrow: /^[1234]/i,\n abbreviated: /^[1234]\\.\\s?[čc]et\\.?/i,\n wide: /^[1234]\\. [čc]etrtletje/i,\n};\nconst parseQuarterPatterns = {\n any: [/1/i, /2/i, /3/i, /4/i],\n};\n\nconst matchMonthPatterns = {\n narrow: /^[jfmasond]/i,\n abbreviated:\n /^(jan\\.|feb\\.|mar\\.|apr\\.|maj|jun\\.|jul\\.|avg\\.|sep\\.|okt\\.|nov\\.|dec\\.)/i,\n wide: /^(januar|februar|marec|april|maj|junij|julij|avgust|september|oktober|november|december)/i,\n};\nconst parseMonthPatterns = {\n narrow: [\n /^j/i,\n /^f/i,\n /^m/i,\n /^a/i,\n /^m/i,\n /^j/i,\n /^j/i,\n /^a/i,\n /^s/i,\n /^o/i,\n /^n/i,\n /^d/i,\n ],\n\n abbreviated: [\n /^ja/i,\n /^fe/i,\n /^mar/i,\n /^ap/i,\n /^maj/i,\n /^jun/i,\n /^jul/i,\n /^av/i,\n /^s/i,\n /^o/i,\n /^n/i,\n /^d/i,\n ],\n\n wide: [\n /^ja/i,\n /^fe/i,\n /^mar/i,\n /^ap/i,\n /^maj/i,\n /^jun/i,\n /^jul/i,\n /^av/i,\n /^s/i,\n /^o/i,\n /^n/i,\n /^d/i,\n ],\n};\n\nconst matchDayPatterns = {\n narrow: /^[nptsčc]/i,\n short: /^(ned\\.|pon\\.|tor\\.|sre\\.|[cč]et\\.|pet\\.|sob\\.)/i,\n abbreviated: /^(ned\\.|pon\\.|tor\\.|sre\\.|[cč]et\\.|pet\\.|sob\\.)/i,\n wide: /^(nedelja|ponedeljek|torek|sreda|[cč]etrtek|petek|sobota)/i,\n};\nconst parseDayPatterns = {\n narrow: [/^n/i, /^p/i, /^t/i, /^s/i, /^[cč]/i, /^p/i, /^s/i],\n any: [/^n/i, /^po/i, /^t/i, /^sr/i, /^[cč]/i, /^pe/i, /^so/i],\n};\n\nconst matchDayPeriodPatterns = {\n narrow: /^(d|po?|z?v|n|z?j|24\\.00|12\\.00)/i,\n any: /^(dop\\.|pop\\.|o?poln(\\.|o[cč]i?)|o?pold(\\.|ne)|z?ve[cč](\\.|er)|(po)?no[cč]i?|popold(ne|an)|jut(\\.|ro)|zjut(\\.|raj))/i,\n};\nconst parseDayPeriodPatterns = {\n narrow: {\n am: /^d/i,\n pm: /^p/i,\n midnight: /^24/i,\n noon: /^12/i,\n morning: /^(z?j)/i,\n afternoon: /^p/i,\n evening: /^(z?v)/i,\n night: /^(n|po)/i,\n },\n any: {\n am: /^dop\\./i,\n pm: /^pop\\./i,\n midnight: /^o?poln/i,\n noon: /^o?pold/i,\n morning: /j/i,\n afternoon: /^pop\\./i,\n evening: /^z?ve/i,\n night: /(po)?no/i,\n },\n};\n\nexport const match = {\n ordinalNumber: buildMatchPatternFn({\n matchPattern: matchOrdinalNumberPattern,\n parsePattern: parseOrdinalNumberPattern,\n valueCallback: (value) => parseInt(value, 10),\n }),\n\n era: buildMatchFn({\n matchPatterns: matchEraPatterns,\n defaultMatchWidth: \"wide\",\n parsePatterns: parseEraPatterns,\n defaultParseWidth: \"any\",\n }),\n\n quarter: buildMatchFn({\n matchPatterns: matchQuarterPatterns,\n defaultMatchWidth: \"wide\",\n parsePatterns: parseQuarterPatterns,\n defaultParseWidth: \"any\",\n valueCallback: (index) => index + 1,\n }),\n\n month: buildMatchFn({\n matchPatterns: matchMonthPatterns,\n defaultMatchWidth: \"wide\",\n parsePatterns: parseMonthPatterns,\n defaultParseWidth: \"wide\",\n }),\n\n day: buildMatchFn({\n matchPatterns: matchDayPatterns,\n defaultMatchWidth: \"wide\",\n parsePatterns: parseDayPatterns,\n defaultParseWidth: \"any\",\n }),\n\n dayPeriod: buildMatchFn({\n matchPatterns: matchDayPeriodPatterns,\n defaultMatchWidth: \"any\",\n parsePatterns: parseDayPeriodPatterns,\n defaultParseWidth: \"any\",\n }),\n};\n","import { formatDistance } from \"./sl/_lib/formatDistance.js\";\nimport { formatLong } from \"./sl/_lib/formatLong.js\";\nimport { formatRelative } from \"./sl/_lib/formatRelative.js\";\nimport { localize } from \"./sl/_lib/localize.js\";\nimport { match } from \"./sl/_lib/match.js\";\n\n/**\n * @category Locales\n * @summary Slovenian locale.\n * @language Slovenian\n * @iso-639-2 slv\n * @author Adam Stradovnik [@Neoglyph](https://github.com/Neoglyph)\n * @author Mato Žgajner [@mzgajner](https://github.com/mzgajner)\n */\nexport const sl = {\n code: \"sl\",\n formatDistance: formatDistance,\n formatLong: formatLong,\n formatRelative: formatRelative,\n localize: localize,\n match: match,\n options: {\n weekStartsOn: 1 /* Monday */,\n firstWeekContainsDate: 1,\n },\n};\n\n// Fallback for modularized imports:\nexport default sl;\n","import { Locale } from 'date-fns';\nimport { sl } from 'date-fns/locale/sl';\nimport { isRef, ref, Ref } from 'vue';\n\nexport const DateTimeLocaleConfig = {\n dateTimeLocale: ref(sl),\n setDateTimeLocale(locale: Locale | Ref<Locale>) {\n if (isRef(locale)) {\n this.dateTimeLocale = locale;\n } else {\n this.dateTimeLocale.value = locale;\n }\n },\n};\n","export type FileProgressCallback = (loaded: number, total: number) => void;\n\n/**\n * Thrown by `FileComms.touch` or `FileComms.delete` when the backend confirms the file identifier no longer\n * exists there (e.g. its keep-alive TTL expired). The component reacts to this specific type by clearing the\n * field and, where a `control` is bound, showing `errorText` as a validation error. Any other thrown error is\n * treated as transient and left entirely to the consumer.\n */\nexport class FileGoneError extends Error {\n constructor(public errorText: string) {\n super(errorText);\n }\n}\n\nexport interface FileComms {\n /**\n * upload is called when a file is added to the input and needs to be uploaded to the backend for storage\n * the component will then set its modelValue to the file identifier returned by this function. when the form\n * is posted, only the identifier will be sent to the backend\n *\n * the method may throw an exception which will mean upload failure\n *\n * @param file the file to be uploaded\n * @param progressCallback callback function to call with current upload progress data.\n * See e.g. axios onUploadProgress for axios post method\n * @return file id\n */\n upload: (file: File, progressCallback?: FileProgressCallback) => Promise<string>;\n\n /**\n * delete is called when the file is removed from the input and needs to be deleted at the backend\n *\n * throw {@link FileGoneError} if the backend reports the file identifier is already gone; any other thrown\n * error is treated as a transient failure\n *\n * @param fileIdentifier the identifier that was returned by upload\n */\n delete: (fileIdentifier: string) => Promise<void>;\n\n /**\n * touch is called at a regular interval (see the `touchInterval` prop / `defaultTouchInterval` setting) to let\n * the backend know that the file is still in play and must not be discarded\n *\n * throw {@link FileGoneError} if the backend reports the file identifier no longer exists; any other thrown\n * error is treated as a transient failure and left to the consumer to act on, if at all\n *\n * @param fileIdentifier the identifier that was returned by upload\n */\n touch: (fileIdentifier: string) => Promise<void>;\n\n /**\n * getDownloadUrl is called when the user asks to download the file currently held by the field. Omit it if\n * the backend offers no way to retrieve an already-uploaded file: the component shows no download control\n * in that case.\n *\n * @param fileIdentifier the identifier that was returned by upload\n * @return a URL the browser can fetch the file from directly (e.g. a signed URL or a same-origin path)\n */\n getDownloadUrl?: (fileIdentifier: string) => string | Promise<string>;\n}\n","<template>\n <messages-widget :message=\"widgetMessage\" :classes=\"widgetClasses\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { MessagesWidget } from '@dynamicforms/vue-forms';\nimport { computed } from 'vue';\n\nimport type { DfInputHintProps } from '../dynamicforms-component-props';\n\nconst props = withDefaults(defineProps<DfInputHintProps>(), {\n errors: '',\n message: '',\n errorClasses: 'text-error',\n messageClasses: '',\n});\n\nconst isError = computed(() => {\n if (props.errors) {\n if (typeof props.errors === 'string') {\n return props.errors.trim().length > 0;\n }\n return props.errors.length > 0;\n }\n return false;\n});\n\nconst widgetMessage = computed(() => {\n return isError.value ? props.errors : props.message;\n});\n\nconst widgetClasses = computed(() => {\n return isError.value ? props.errorClasses : props.messageClasses;\n});\n</script>\n\n<style scoped></style>\n","<template>\n <messages-widget :message=\"widgetMessage\" :classes=\"widgetClasses\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { MessagesWidget } from '@dynamicforms/vue-forms';\nimport { computed } from 'vue';\n\nimport type { DfInputHintProps } from '../dynamicforms-component-props';\n\nconst props = withDefaults(defineProps<DfInputHintProps>(), {\n errors: '',\n message: '',\n errorClasses: 'text-error',\n messageClasses: '',\n});\n\nconst isError = computed(() => {\n if (props.errors) {\n if (typeof props.errors === 'string') {\n return props.errors.trim().length > 0;\n }\n return props.errors.length > 0;\n }\n return false;\n});\n\nconst widgetMessage = computed(() => {\n return isError.value ? props.errors : props.message;\n});\n\nconst widgetClasses = computed(() => {\n return isError.value ? props.errorClasses : props.messageClasses;\n});\n</script>\n\n<style scoped></style>\n","<template>\n <div class=\"df-label\" :class=\"{ 'allow-wrap': allowWrap }\">\n <template v-if=\"label.icon\">\n <cached-icon v-if=\"label.iconComponent === 'v-icon'\" :name=\"label.icon\" size=\"1.25em\" />\n <v-img v-else-if=\"label.iconComponent === 'v-img'\" class=\"icon\" :src=\"label.icon\" />\n <component :is=\"label.iconComponent\" v-else :src=\"label.icon\" />\n </template>\n <vue-markdown\n v-if=\"lbl instanceof MdString\"\n class=\"markdown\"\n :source=\"lbl.toString()\"\n :options=\"lbl.options\"\n :plugins=\"lbl.plugins\"\n />\n <template v-else>{{ lbl }}</template>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { MdString } from '@dynamicforms/vue-forms';\nimport { computed } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\nimport VueMarkdown from 'vue-markdown-render';\n\nimport type { DfLabelProps } from '../dynamicforms-component-props';\n\nconst props = defineProps<DfLabelProps>();\n\nconst lbl = computed(() => (props.data ? props.data.label : props.label.text));\n</script>\n\n<style>\n.df-label {\n display: flex;\n align-items: center;\n gap: 2px;\n white-space: nowrap;\n justify-content: flex-start;\n}\n\n.df-label.allow-wrap {\n white-space: initial;\n}\n\n.df-label .icon {\n width: 1.25em;\n}\n\n.df-label .markdown :first-child,\n.df-label .markdown :last-child {\n margin-top: 0 !important;\n padding-top: 0 !important;\n margin-bottom: 0 !important;\n padding-bottom: 0 !important;\n line-height: 1.35em !important; /* inspired by vitepress' aggressive settings */\n}\n</style>\n","<template>\n <div class=\"df-label\" :class=\"{ 'allow-wrap': allowWrap }\">\n <template v-if=\"label.icon\">\n <cached-icon v-if=\"label.iconComponent === 'v-icon'\" :name=\"label.icon\" size=\"1.25em\" />\n <v-img v-else-if=\"label.iconComponent === 'v-img'\" class=\"icon\" :src=\"label.icon\" />\n <component :is=\"label.iconComponent\" v-else :src=\"label.icon\" />\n </template>\n <vue-markdown\n v-if=\"lbl instanceof MdString\"\n class=\"markdown\"\n :source=\"lbl.toString()\"\n :options=\"lbl.options\"\n :plugins=\"lbl.plugins\"\n />\n <template v-else>{{ lbl }}</template>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { MdString } from '@dynamicforms/vue-forms';\nimport { computed } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\nimport VueMarkdown from 'vue-markdown-render';\n\nimport type { DfLabelProps } from '../dynamicforms-component-props';\n\nconst props = defineProps<DfLabelProps>();\n\nconst lbl = computed(() => (props.data ? props.data.label : props.label.text));\n</script>\n\n<style>\n.df-label {\n display: flex;\n align-items: center;\n gap: 2px;\n white-space: nowrap;\n justify-content: flex-start;\n}\n\n.df-label.allow-wrap {\n white-space: initial;\n}\n\n.df-label .icon {\n width: 1.25em;\n}\n\n.df-label .markdown :first-child,\n.df-label .markdown :last-child {\n margin-top: 0 !important;\n padding-top: 0 !important;\n margin-bottom: 0 !important;\n padding-bottom: 0 !important;\n line-height: 1.35em !important; /* inspired by vitepress' aggressive settings */\n}\n</style>\n","import { FieldDensity, type FieldVariant } from '@/helpers/input-base';\n\nexport interface VuetifyInputsSettings {\n defaultVariant?: FieldVariant;\n defaultDensity?: FieldDensity;\n /** Milliseconds between `<df-file>`/`<df-image>` keep-alive touches; overridable per field by their\n * `touchInterval` prop. Defaults to 60000 when neither is set. */\n defaultTouchInterval?: number;\n}\n\nexport const vuetifyInputsSettingsKey = Symbol('vuetifyInputsSettingsKey');\n","import Form, { MdString, ValidationErrorRenderContent } from '@dynamicforms/vue-forms';\nimport { isEmpty, isString } from 'lodash-es';\nimport { computed, inject, nextTick, ref, shallowRef, toRaw } from 'vue';\n\nimport { VuetifyInputsSettings, vuetifyInputsSettingsKey } from './settings';\n\nexport class Label {\n constructor(\n public text: string,\n public icon?: string,\n public iconComponent: string = 'v-icon',\n ) {}\n}\n\nexport type FieldVariant = 'outlined' | 'plain' | 'underlined' | 'filled' | 'solo' | 'solo-inverted' | 'solo-filled';\nexport type VuetifyDensity = 'default' | 'comfortable' | 'compact';\nexport type FieldDensity = 'default' | 'comfortable' | 'compact' | 'inline';\n/** Vuetify's own `size` prop (`v-btn`, `v-icon`, ...) also accepts an arbitrary CSS length or number, so this\n * keeps that but still offers the named sizes for autocomplete: `(string & {})` is a plain `string` to the type\n * checker (any string is still assignable) but not to a union with string literals, which is what makes an IDE\n * suggest the literals instead of collapsing them into `string`. */\nexport type VuetifyButtonSize = 'x-small' | 'small' | 'default' | 'large' | 'x-large' | (string & {}) | number;\n\n/**\n * The presentation an element carries for the components in this library.\n *\n * Every one of these is also a prop, and the prop wins where both state something: a call site is more specific\n * than the element it renders. What the element carries is what a form declared in code says about itself, so a\n * field that names its own label needs no attribute at the tag that draws it.\n *\n * `Extras` is @dynamicforms/vue-forms' augmentation point for exactly this, so these properties are typed on every\n * element in an application that installs this library, the fields written inline in a `Group` declaration\n * included.\n */\ndeclare module '@dynamicforms/vue-forms' {\n interface Extras {\n label?: string | Label | MdString;\n placeholder?: string;\n helpText?: string;\n hint?: string;\n cssClass?: string;\n density?: FieldDensity;\n variant?: FieldVariant;\n }\n}\n\nexport interface BaseProps<T = any> {\n control?: Form.FieldBase<T>;\n modelValue?: T;\n label?: string | Label | MdString;\n errors?: string[];\n placeholder?: string;\n helpText?: string;\n hint?: string;\n enabled?: boolean;\n visibility?: Form.DisplayMode | string;\n cssClass?: string;\n clearable?: boolean;\n passthroughAttrs?: Record<string, any>;\n density?: FieldDensity;\n variant?: FieldVariant;\n}\n\nexport const defaultBaseProps = { enabled: undefined, clearable: true };\n\nexport interface BaseEmits<T = any> {\n (e: 'update:modelValue', value: T): void;\n (e: 'click:clear'): void;\n}\n\nexport function useInputBase<T = any>(props: BaseProps<T>, emit: BaseEmits<T>) {\n const settings = inject<VuetifyInputsSettings>(vuetifyInputsSettingsKey, {});\n const injectedDensity = inject<FieldDensity | null>('field-density', null);\n const injectedVariant = inject<FieldVariant | null>('field-variant', null);\n const internalValue = ref<T | null>(null);\n\n // A write is not a statement about what the control ends up holding. A ValueChangedAction may write a different\n // value back, a disabled field drops the write, and a handler that throws unwinds it. The rendered control has\n // the written value in its DOM by then, so it is the read here that has to correct it - and where the value the\n // control ends up holding is the one it started with, as under a rule that puts back the five characters a\n // six-character write exceeded, the read does not move and Vue schedules no render at all. Holding the written\n // value for one tick makes the read change twice, so the repaint that restores what the control holds happens.\n const pendingWrite = shallowRef<{ value: T } | null>(null);\n\n const value = computed({\n get(): T {\n if (pendingWrite.value) return pendingWrite.value.value;\n if (props.control) return props.control.value as T;\n if (props.modelValue === undefined) return internalValue.value as T;\n return props.modelValue as T;\n },\n set(newValue: T) {\n try {\n if (props.control) props.control.value = newValue;\n } finally {\n // compared as the write was made: an element holds its state behind reactive(), so an array or an object\n // reads back as a proxy of what was written and an identity comparison would answer that every such write\n // was refused. Object.is over the raw objects answers for NaN as well\n if (props.control && !Object.is(toRaw(props.control.value as any), toRaw(newValue as any))) {\n pendingWrite.value = { value: newValue };\n nextTick(() => {\n pendingWrite.value = null;\n });\n }\n }\n if (props.modelValue === undefined) internalValue.value = newValue;\n emit('update:modelValue', props.control ? (props.control.value as T) : newValue);\n },\n });\n\n if (props.control && !(props.control instanceof Form.FieldBase)) {\n throw new Error('control prop is not a vue-form control instance');\n }\n\n const controlTouch = computed({\n get() {\n return props.control!.touched;\n },\n set(val: boolean) {\n props.control!.touched = val;\n },\n });\n const touched = props.control ? controlTouch : ref(false);\n const valid = computed(() => (props.control ? props.control.valid : true));\n const errors = computed(() =>\n props.control ? props.control.errors : (props.errors || []).map((error) => new ValidationErrorRenderContent(error)),\n );\n const anyErrors = computed(() => (touched.value && errors.value.length > 0 ? ' ' : undefined));\n const showErrors = computed(() => (touched.value ? errors.value : undefined));\n // a field inside a disabled section is drawn disabled: effectiveEnabled is false where the element or any\n // container above it is disabled, which is the question a rendered input asks\n const enabled = computed(() => (props.control ? props.control.effectiveEnabled : props.enabled !== false));\n // A control resolves its own mode - vue-forms refuses anything that is not a DisplayMode constant and reads a\n // name case-insensitively. The prop is resolved the same way, so `visibility=\"hidden\"` states what it looks\n // like it states and an unrecognised mode is refused here as loudly as it is there.\n const visibility = computed(() => {\n if (props.control) return props.control.visibility;\n if (props.visibility == null) return Form.DisplayMode.FULL;\n return Form.DisplayMode.fromAny(props.visibility);\n });\n const isRendered = computed(() => visibility.value !== Form.DisplayMode.SUPPRESS);\n const visibilityClass = computed(() => ({\n 'd-none': visibility.value === Form.DisplayMode.HIDDEN,\n invisible: visibility.value === Form.DisplayMode.INVISIBLE,\n }));\n // the presentation the bound element carries: what a prop does not state is taken from here before any default\n const extra = computed(() => props.control?.extra ?? {});\n\n const label = computed((): Label => {\n const stated = props.label ?? extra.value.label;\n return isString(stated || '') ? new Label(<string>stated || '') : <Label>stated;\n });\n const placeholder = computed(() => props.placeholder ?? extra.value.placeholder ?? '');\n const helpText = computed(() => props.helpText ?? extra.value.helpText ?? '');\n const hint = computed(() => props.hint ?? extra.value.hint ?? '');\n const cssClass = computed(() => props.cssClass ?? extra.value.cssClass ?? '');\n\n const density = computed(\n (): FieldDensity => props.density ?? extra.value.density ?? injectedDensity ?? settings.defaultDensity ?? 'default',\n );\n const boundDensity = computed((): VuetifyDensity => (density.value === 'inline' ? 'default' : density.value));\n const variant = computed(\n (): FieldVariant =>\n props.variant ?? extra.value.variant ?? injectedVariant ?? settings.defaultVariant ?? 'underlined',\n );\n\n return {\n value,\n valid,\n enabled,\n errors,\n showErrors,\n visibility,\n isRendered,\n visibilityClass,\n label,\n touched,\n density,\n densityClass: computed(() => `df-density-${density.value}`),\n\n vuetifyBindings: computed(() => ({\n name: props.control?.fieldName,\n class: cssClass.value,\n\n density: boundDensity.value,\n variant: variant.value,\n\n label: label.value.text,\n errorMessages: anyErrors.value,\n // 'error-count': errors?.value.length || 0,\n readonly: !enabled.value,\n disabled: !enabled.value,\n\n placeholder: placeholder.value,\n 'persistent-placeholder': !isEmpty(placeholder.value),\n\n hint: hint.value,\n persistentHint: true, // we want persistent hint always\n hideDetails: <boolean | 'auto' | undefined>'auto', // we want to hide the hint element when hint isn't there\n helpText: helpText.value,\n\n ...(props.passthroughAttrs || {}),\n })),\n };\n}\n","<template>\n <v-input\n v-if=\"isRendered\"\n :name=\"vuetifyBindings.name\"\n :density=\"vuetifyBindings.density\"\n :hint=\"vuetifyBindings.hint\"\n :persistent-hint=\"vuetifyBindings.persistentHint\"\n :hide-details=\"vuetifyBindings.hideDetails\"\n :error-messages=\"vuetifyBindings.errorMessages\"\n :class=\"[cssClass, visibilityClass]\"\n >\n <v-field\n :variant=\"vuetifyBindings.variant\"\n :density=\"vuetifyBindings.density\"\n :label=\"vuetifyBindings.label\"\n :disabled=\"vuetifyBindings.disabled\"\n :clearable=\"isClearable\"\n :persistent-clear=\"true\"\n :dirty=\"!!value || !!vuetifyBindings.placeholder\"\n :active=\"focused\"\n :loading=\"loading\"\n @click:clear=\"emits('click:clear')\"\n @update:focused=\"(isFocused) => setFocused(isFocused)\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #default=\"slotProps\">\n <div class=\"d-flex w-100 df-style-resetting df-sub-field\"><slot v-bind=\"slotProps\" /></div>\n </template>\n <template #loader=\"loaderProps\"><slot name=\"loader\" v-bind=\"loaderProps\" /></template>\n <template v-if=\"$slots['prepend-inner']\" #prepend-inner=\"prependInnerProps\">\n <slot name=\"prepend-inner\" v-bind=\"prependInnerProps\" />\n </template>\n </v-field>\n <template #message=\"{ message }\">\n <df-input-hint :message=\"message\" :errors=\"showErrors\" />\n </template>\n <template v-if=\"$slots.prepend\" #prepend=\"prependProps\"><slot name=\"prepend\" v-bind=\"prependProps\" /></template>\n </v-input>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, unref } from 'vue';\n\nimport DfInputHint from './df-input-hint.vue';\nimport DfLabel from './df-label.vue';\nimport { BaseEmits, BaseProps, useInputBase } from './input-base';\n\nconst props = defineProps<BaseProps & { loading?: boolean }>();\nconst emits = defineEmits<BaseEmits & { (e: 'blur'): void }>();\n\nconst { isRendered, label, showErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(props, emits);\n\nconst isClearable = computed(() => !!(unref(props.clearable) && unref(value)));\nconst focused = ref<boolean>(false);\n\nfunction setFocused(isFocused: boolean) {\n focused.value = isFocused;\n if (!isFocused) {\n touched.value = true;\n emits('blur');\n }\n}\n</script>\n\n<style>\n.df-style-resetting .v-field__overlay {\n background-color: transparent;\n}\n.df-style-resetting .v-field__outline::before,\n.df-style-resetting .v-field__outline::after {\n content: none !important;\n}\n\n.df-sub-field {\n max-height: var(--v-input-control-height);\n min-height: max(\n var(--v-input-control-height, 56px),\n 1.5rem + var(--v-field-input-padding-top) + var(--v-field-input-padding-bottom)\n );\n}\n\n.df-density-inline .df-sub-field {\n min-height: revert;\n}\n\n.rtf-editor .df-sub-field {\n max-height: revert;\n}\n</style>\n","<template>\n <v-input\n v-if=\"isRendered\"\n :name=\"vuetifyBindings.name\"\n :density=\"vuetifyBindings.density\"\n :hint=\"vuetifyBindings.hint\"\n :persistent-hint=\"vuetifyBindings.persistentHint\"\n :hide-details=\"vuetifyBindings.hideDetails\"\n :error-messages=\"vuetifyBindings.errorMessages\"\n :class=\"[cssClass, visibilityClass]\"\n >\n <v-field\n :variant=\"vuetifyBindings.variant\"\n :density=\"vuetifyBindings.density\"\n :label=\"vuetifyBindings.label\"\n :disabled=\"vuetifyBindings.disabled\"\n :clearable=\"isClearable\"\n :persistent-clear=\"true\"\n :dirty=\"!!value || !!vuetifyBindings.placeholder\"\n :active=\"focused\"\n :loading=\"loading\"\n @click:clear=\"emits('click:clear')\"\n @update:focused=\"(isFocused) => setFocused(isFocused)\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #default=\"slotProps\">\n <div class=\"d-flex w-100 df-style-resetting df-sub-field\"><slot v-bind=\"slotProps\" /></div>\n </template>\n <template #loader=\"loaderProps\"><slot name=\"loader\" v-bind=\"loaderProps\" /></template>\n <template v-if=\"$slots['prepend-inner']\" #prepend-inner=\"prependInnerProps\">\n <slot name=\"prepend-inner\" v-bind=\"prependInnerProps\" />\n </template>\n </v-field>\n <template #message=\"{ message }\">\n <df-input-hint :message=\"message\" :errors=\"showErrors\" />\n </template>\n <template v-if=\"$slots.prepend\" #prepend=\"prependProps\"><slot name=\"prepend\" v-bind=\"prependProps\" /></template>\n </v-input>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, unref } from 'vue';\n\nimport DfInputHint from './df-input-hint.vue';\nimport DfLabel from './df-label.vue';\nimport { BaseEmits, BaseProps, useInputBase } from './input-base';\n\nconst props = defineProps<BaseProps & { loading?: boolean }>();\nconst emits = defineEmits<BaseEmits & { (e: 'blur'): void }>();\n\nconst { isRendered, label, showErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(props, emits);\n\nconst isClearable = computed(() => !!(unref(props.clearable) && unref(value)));\nconst focused = ref<boolean>(false);\n\nfunction setFocused(isFocused: boolean) {\n focused.value = isFocused;\n if (!isFocused) {\n touched.value = true;\n emits('blur');\n }\n}\n</script>\n\n<style>\n.df-style-resetting .v-field__overlay {\n background-color: transparent;\n}\n.df-style-resetting .v-field__outline::before,\n.df-style-resetting .v-field__outline::after {\n content: none !important;\n}\n\n.df-sub-field {\n max-height: var(--v-input-control-height);\n min-height: max(\n var(--v-input-control-height, 56px),\n 1.5rem + var(--v-field-input-padding-top) + var(--v-field-input-padding-bottom)\n );\n}\n\n.df-density-inline .df-sub-field {\n min-height: revert;\n}\n\n.rtf-editor .df-sub-field {\n max-height: revert;\n}\n</style>\n","import { createTranslatable } from '@dynamicforms/translatable';\n\nexport const { strings: translatableStrings, translateStrings } = createTranslatable({\n Yes: 'Yes',\n No: 'No',\n Close: 'Close',\n Paragraph: 'Paragraph',\n Heading1: 'Heading 1',\n Heading2: 'Heading 2',\n Heading3: 'Heading 3',\n Heading4: 'Heading 4',\n Heading5: 'Heading 5',\n Heading6: 'Heading 6',\n Downloadable: 'Downloadable',\n ArticleCategory: 'Article category',\n Title: 'Title',\n Subtitle: 'Subtitle',\n InfoBox: 'Info box',\n SideQuote: 'Side quote',\n Marker: 'Marker',\n Spoiler: 'Spoiler',\n CodeDark: 'Code (dark)',\n CodeBright: 'Code (bright)',\n Undo: 'Undo',\n Redo: 'Redo',\n SelectAll: 'Select all',\n Bold: 'Bold',\n Italic: 'Italic',\n HorizontalLine: 'Horizontal line',\n Blockquote: 'Block quote',\n BulletedList: 'Bulleted list',\n NumberedList: 'Numbered list',\n Outdent: 'Decrease indent',\n Indent: 'Increase indent',\n AlignLeft: 'Align left',\n AlignCenter: 'Align center',\n AlignRight: 'Align right',\n AlignJustify: 'Justify',\n Link: 'Link',\n LinkUrl: 'URL',\n LinkApply: 'Apply',\n LinkRemove: 'Remove link',\n Image: 'Image',\n ImageUrl: 'Image URL',\n ImageUpload: 'Upload image',\n ImageInsert: 'Insert',\n ImageDropHint: 'Drop image here or click to browse',\n ImageReplace: 'Replace image',\n ImageDownload: 'Download image',\n FileDownload: 'Download file',\n Table: 'Table',\n TableInsert: 'Insert table',\n TableAddRowAbove: 'Add row above',\n TableAddRowBelow: 'Add row below',\n TableDeleteRow: 'Delete row',\n TableAddColumnBefore: 'Add column before',\n TableAddColumnAfter: 'Add column after',\n TableDeleteColumn: 'Delete column',\n TableToggleHeaderRow: 'Toggle header row',\n TableDeleteTable: 'Delete table',\n Style: 'Style',\n MediaEmbed: 'Insert media',\n MediaEmbedUrl: 'Video URL',\n MediaEmbedInsert: 'Insert',\n InvalidHexColor: 'Not a valid hex string.',\n});\n","/**\n * DisplayMode enum provides an enumeration for supported ways of rendering a particular object in the DOM\n */\nenum ActionDisplayStyle {\n // This enum is actually declared in dynamicforms.action.py\n BUTTON = 0, // action should render as a button\n TEXT = 1, // action should render as a link text\n}\n\nexport const defaultDisplayStyle = ActionDisplayStyle.BUTTON;\n\n// eslint-disable-next-line @typescript-eslint/no-namespace, no-redeclare\nnamespace ActionDisplayStyle {\n export function fromString(mode: string): ActionDisplayStyle {\n if (mode.toUpperCase() === 'BUTTON') return ActionDisplayStyle.BUTTON;\n if (mode.toUpperCase() === 'TEXT') return ActionDisplayStyle.TEXT;\n return defaultDisplayStyle;\n }\n\n export function fromAny(mode: any): ActionDisplayStyle {\n const input = typeof mode === 'number' ? mode : ActionDisplayStyle.fromString(mode as string);\n if (Object.values(ActionDisplayStyle).includes(input)) return input;\n return defaultDisplayStyle;\n }\n\n export function isDefined(mode: number | string): boolean {\n const check = typeof mode === 'number' ? mode : ActionDisplayStyle.fromString(mode as string);\n return Object.values(ActionDisplayStyle).includes(check);\n }\n}\n\nObject.freeze(ActionDisplayStyle);\n\nexport { ActionDisplayStyle };\n","import { isPlainObject } from 'lodash-es';\nimport { computed } from 'vue';\nimport { useDisplay } from 'vuetify';\n\nexport const responsiveBreakpoints = ['xs', 'sm', 'md', 'lg', 'xl'] as const;\nexport type BreakpointNames = (typeof responsiveBreakpoints)[number];\n/**\n * A set of options and the per-breakpoint sets that restate parts of it. `B` is what a breakpoint may state,\n * and defaults to the whole of `T`; a subclass narrows it where a member belongs to the object as a whole rather\n * than to one screen width.\n */\nexport type BreakpointsJSON<T extends Record<string, any>, B extends Record<string, any> = T> = T &\n Partial<Record<BreakpointNames, B>>;\n\nexport abstract class ResponsiveRenderOptions<T extends Record<string, any>> {\n protected readonly _value: BreakpointsJSON<T>;\n\n constructor(data?: BreakpointsJSON<T>) {\n this._value = this.cleanBreakpoint(data as T, true)!;\n if (data) {\n responsiveBreakpoints.forEach((bp) => {\n const options = this.cleanBreakpoint(data[bp]);\n if (options) this._value[bp] = options;\n });\n }\n }\n\n getOptionsForBreakpoint(breakpoint: BreakpointNames): T {\n // a base that states nothing cleans to null, and the breakpoints above it still have options to resolve\n const result = (this.cleanBreakpoint(this._value as T) ?? ({} as T)) as BreakpointsJSON<T>;\n for (const bp of responsiveBreakpoints) {\n // the fields that cascade are the ones each breakpoint states, so a field named at a breakpoint and\n // nowhere else still reaches the result\n const bpData = this._value[bp] ?? {};\n for (const field of Object.keys(bpData)) {\n const value = (<any>bpData)[field];\n // a breakpoint states what it changes; a field it says nothing about keeps cascading\n if (value == null) continue;\n if (isPlainObject(value)) {\n // shallow, so a breakpoint restates single keys of an options object rather than the whole of it. A\n // nested object is a value like any other and is replaced whole. Only plain objects merge: a Date, a\n // Map or a class instance would come out of a spread as its own properties without its prototype.\n (<any>result)[field] = { ...(<any>result)[field], ...value };\n } else {\n (<any>result)[field] = value;\n }\n }\n if (bp === breakpoint) break;\n }\n return result;\n }\n\n /**\n * Normalizes one breakpoint's options. The merge reads `null` and `undefined` as \"this breakpoint says\n * nothing about that field\", so a field the breakpoint does not state has to come back as `undefined` rather\n * than as an empty value - an empty array or string returned here reads as a breakpoint deliberately emptying\n * what it inherited.\n */\n protected abstract cleanBreakpoint(bp?: T, defaultIfEmpty?: boolean): T | null;\n}\n\nexport function getBreakpointName(dp: ReturnType<typeof useDisplay>): BreakpointNames {\n if (dp.xlAndUp.value) return 'xl';\n if (dp.lgAndUp.value) return 'lg';\n if (dp.mdAndUp.value) return 'md';\n if (dp.smAndUp.value) return 'sm';\n return 'xs';\n}\n\nexport function useBreakpoint() {\n const display = useDisplay();\n\n return computed<BreakpointNames>(() => getBreakpointName(display));\n}\n","import { ActionValue } from '@dynamicforms/vue-forms';\nimport { isBoolean, isEmpty, isObjectLike, isPlainObject, isString } from 'lodash-es';\n\nimport { ActionDisplayStyle } from './action-display-style';\nimport { BreakpointNames, BreakpointsJSON, ResponsiveRenderOptions } from './responsive-render-options';\n\nexport interface ActionRenderOptions extends ActionValue {\n /** The text of the action, rendered when {@link showLabel} is set and the text is not empty. `ActionValue`\n * types this `unknown`, leaving what a label is to the rendering library; here it is a string. */\n label?: string;\n /** The icon of the action, a name `vue-cached-icon` resolves, rendered when {@link showIcon} is set and the\n * name is not empty. Typed here for the same reason `label` is. */\n icon?: string;\n /** Unique identifier for the action. Purely informational to `<df-actions>` itself - it is not used for\n * rendering - but by convention should match the key under which the action is registered in a\n * `FormActions` (`Record<string, Action>`) map passed to `@dynamicforms/vuetify-modal-form-kit`'s\n * `modal.message()`/`modal.yesNo()`/etc. That map key (or the action's `fieldName`, when it's part of a\n * `Form.Group`) - not this `name` field - is what the modal's promise actually resolves with; keeping them\n * in sync is what lets callers do e.g. `if (await modal.yesNo(...) === 'yes')`. */\n name?: string;\n /** How the action is rendered: {@link ActionDisplayStyle.BUTTON} for a tonal `<v-btn>`, or\n * {@link ActionDisplayStyle.TEXT} for a text-variant `<v-btn>`. */\n renderAs?: ActionDisplayStyle;\n /** Whether the label is shown. If `label` is empty, the label is never shown regardless of this flag. */\n showLabel?: boolean;\n /** Whether the icon is shown. If `icon` is empty, the icon is never shown regardless of this flag. */\n showIcon?: boolean;\n /** Marks this as the action to trigger on Enter when rendered inside `<df-modal>` (see that component's\n * `onKeydown` in `@dynamicforms/vuetify-modal-form-kit`) - e.g. a \"Save\" or \"Yes\" action. In `<df-actions>` it\n * also colors the button `primary`, unless overridden via `passthroughAttrs.color`. At most one action in a\n * given set should set this. */\n defaultConfirm?: boolean;\n /** Marks this as the action to trigger on Escape when rendered inside `<df-modal>` (see that component's\n * `onKeydown` in `@dynamicforms/vuetify-modal-form-kit`) - e.g. a \"Cancel\" or \"No\" action. In `<df-actions>` it\n * also colors the button `secondary`, unless overridden via `passthroughAttrs.color`. At most one action in a\n * given set should set this (an action such as `Action.closeAction()` may set both `defaultConfirm` and\n * `defaultReject` so it fires on either key). */\n defaultReject?: boolean;\n /** Additional props/attrs forwarded verbatim to the rendered `<v-btn>` (e.g. `color`, `loading`, `density`,\n * `rounded`, `block`, `prependIcon`, ...), taking precedence over `<df-actions>`'s own computed bindings\n * (`variant`, `color`, `disabled`). Mirrors the `passthroughAttrs` convention used by `df-input`/`df-file`/etc\n * (see `helpers/input-base.ts`); it has to live on the action's value here because `<df-actions>` renders a\n * whole array of buttons, not just one. */\n passthroughAttrs?: Record<string, any>;\n}\n/**\n * What one breakpoint of an action's value may state: the members that describe how the action is drawn.\n * `name`, `defaultConfirm` and `defaultReject` are not among them - which key a modal resolves with, and which\n * key fires the action, are properties of the action itself and do not depend on the width of the screen.\n */\nexport type ActionBreakpointRenderOptions = Omit<ActionRenderOptions, 'name' | 'defaultConfirm' | 'defaultReject'>;\nexport type ActionBreakpointOptions = BreakpointsJSON<ActionRenderOptions, ActionBreakpointRenderOptions>;\n\nexport class ResponsiveActionRenderOptions extends ResponsiveRenderOptions<ActionRenderOptions> {\n protected cleanBreakpoint(bp?: ActionRenderOptions, defaultIfEmpty: boolean = false): ActionRenderOptions | null {\n if ((!bp || !isObjectLike(bp)) && !defaultIfEmpty) return null;\n\n const result: ActionRenderOptions = {};\n if (defaultIfEmpty) {\n result.renderAs = ActionDisplayStyle.BUTTON;\n result.showLabel = true;\n result.showIcon = true;\n }\n\n if (bp) {\n if (bp.renderAs != null) result.renderAs = ActionDisplayStyle.fromAny(bp.renderAs);\n if (isString(bp.label)) result.label = bp.label;\n if (isString(bp.icon)) result.icon = bp.icon;\n if (isBoolean(bp.showLabel)) result.showLabel = bp.showLabel;\n if (isBoolean(bp.showIcon)) result.showIcon = bp.showIcon;\n if (isString(bp.name)) result.name = bp.name;\n if (isBoolean(bp.defaultConfirm)) result.defaultConfirm = bp.defaultConfirm;\n if (isBoolean(bp.defaultReject)) result.defaultReject = bp.defaultReject;\n // copied rather than kept by identity, so the cascade's shallow merge of a later breakpoint's attrs does\n // not write into the object the action holds\n if (isPlainObject(bp.passthroughAttrs)) result.passthroughAttrs = { ...bp.passthroughAttrs };\n }\n\n return Object.keys(result).length ? result : null;\n }\n}\n\n/**\n * What one action renders as at `breakpoint`, read off the value of any `Action`. The members\n * `ActionRenderOptions` adds over `ActionValue` are taken where the value carries them and defaulted where it does\n * not, so an action holding nothing but a label - which is all a `@dynamicforms/vue-forms` `Action` declares -\n * renders as a button showing that label.\n *\n * `label` and `icon` come back only where the matching flag says they are shown, and the flags come back false\n * where there is no text or name to show, so a caller renders each member on its own flag and never on emptiness.\n */\nexport function getRenderOptionsForBreakpoint(value: ActionValue, breakpoint: BreakpointNames): ActionRenderOptions {\n const options = new ResponsiveActionRenderOptions(value as ActionBreakpointOptions);\n const partial = options.getOptionsForBreakpoint(breakpoint);\n return {\n name: partial.name,\n label: partial.showLabel ? partial.label : undefined,\n icon: partial.showIcon ? partial.icon : undefined,\n renderAs: partial.renderAs,\n showLabel: isString(partial.label) && !isEmpty(partial.label) ? partial.showLabel : false,\n showIcon: isString(partial.icon) && !isEmpty(partial.icon) ? partial.showIcon : false,\n defaultConfirm: partial.defaultConfirm,\n defaultReject: partial.defaultReject,\n passthroughAttrs: partial.passthroughAttrs,\n };\n}\n","import { Action as FormAction, IFieldConstructorParams } from '@dynamicforms/vue-forms';\nimport { isEmpty, isString } from 'lodash-es';\nimport { computed, Ref } from 'vue';\n\nimport { translatableStrings } from '../translations';\n\nimport { ActionDisplayStyle } from './action-display-style';\nimport { ActionBreakpointOptions, getRenderOptionsForBreakpoint } from './action-render-options';\nimport { BreakpointNames } from './responsive-render-options';\n\nclass Action extends FormAction<ActionBreakpointOptions> {\n /** @see getRenderOptionsForBreakpoint, which answers the same for the value of any `Action` */\n getBreakpointValue(breakpoint: Ref<BreakpointNames>) {\n return computed(() => getRenderOptionsForBreakpoint(this.value, breakpoint.value));\n }\n\n /** @see ActionRenderOptions.name */\n get name() {\n return this.value.name;\n }\n\n /**\n * The label as this action renders it: the text where {@link ActionRenderOptions.showLabel} states it is shown,\n * and `undefined` where it is not. `label` is the base class's, and answers the text whatever the flag says.\n */\n get renderedLabel() {\n return this.value.showLabel ? this.value.label : undefined;\n }\n\n /** @see ActionRenderOptions.showLabel */\n get showLabel() {\n return isString(this.value.label) && !isEmpty(this.value.label) ? this.value.showLabel : false;\n }\n\n /**\n * The icon as this action renders it: the name where {@link ActionRenderOptions.showIcon} states it is shown,\n * and `undefined` where it is not. `icon` is the base class's, and answers the name whatever the flag says.\n */\n get renderedIcon() {\n return this.value.showIcon ? this.value.icon : undefined;\n }\n\n /** @see ActionRenderOptions.showIcon */\n get showIcon() {\n return isString(this.value.icon) && !isEmpty(this.value.icon) ? this.value.showIcon : false;\n }\n\n /** @see ActionRenderOptions.renderAs */\n get renderAs() {\n return this.value.renderAs;\n }\n\n /** @see ActionRenderOptions.defaultConfirm */\n get defaultConfirm() {\n return this.value.defaultConfirm;\n }\n\n /** @see ActionRenderOptions.defaultReject */\n get defaultReject() {\n return this.value.defaultReject;\n }\n\n /** @see ActionRenderOptions.passthroughAttrs */\n get passthroughAttrs() {\n return this.value.passthroughAttrs;\n }\n\n static closeAction(data?: Partial<IFieldConstructorParams<ActionBreakpointOptions>>) {\n const init: Partial<IFieldConstructorParams<ActionBreakpointOptions>> = {\n ...(data ?? {}), // any properties in data should overwrite properties in the constant\n value: {\n name: 'close',\n label: translatableStrings.Close,\n icon: 'ion-close-outline',\n renderAs: ActionDisplayStyle.BUTTON,\n showLabel: true,\n showIcon: true,\n },\n };\n init.value = { ...init.value, ...(data?.value ?? {}) }; // data may only contain partial info of the value\n return new Action(init);\n }\n\n static yesAction(data?: Partial<IFieldConstructorParams<ActionBreakpointOptions>>) {\n const init: Partial<IFieldConstructorParams<ActionBreakpointOptions>> = {\n ...(data ?? {}), // any properties in data should overwrite properties in the constant\n value: {\n name: 'yes',\n label: translatableStrings.Yes,\n icon: 'ion-thumbs-up-outline',\n renderAs: ActionDisplayStyle.BUTTON,\n showLabel: true,\n showIcon: true,\n },\n };\n init.value = { ...init.value, ...(data?.value ?? {}) }; // data may only contain partial info of the value\n return new Action(init);\n }\n\n static noAction(data?: Partial<IFieldConstructorParams<ActionBreakpointOptions>>) {\n const init: Partial<IFieldConstructorParams<ActionBreakpointOptions>> = {\n ...(data ?? {}), // any properties in data should overwrite properties in the constant\n value: {\n name: 'no',\n label: translatableStrings.No,\n icon: 'ion-thumbs-down-outline',\n renderAs: ActionDisplayStyle.BUTTON,\n showLabel: true,\n showIcon: true,\n },\n };\n init.value = { ...init.value, ...(data?.value ?? {}) }; // data may only contain partial info of the value\n return new Action(init);\n }\n}\n\nexport { Action };\n","import Form, { ValidationErrorRenderContent } from '@dynamicforms/vue-forms';\nimport { inject, onBeforeUnmount, ref, watch, type Ref } from 'vue';\n\nimport { FileComms, FileGoneError } from './df-file.interface';\nimport { VuetifyInputsSettings, vuetifyInputsSettingsKey } from './settings';\n\n/**\n * Runs the `comms.touch` keep-alive interval for `<df-file>`/`<df-image>` while `value` holds a file\n * identifier: starts it once `value` becomes truthy, stops it once it doesn't, and stops it on unmount.\n * `onGone` is called with `err.errorText` whenever a touch rejects with a {@link FileGoneError}; any other\n * rejection is left unhandled beyond that (it's a transient failure, for the consumer to act on if at all).\n */\nexport function useFileTouchKeepAlive(\n value: Ref<string | null>,\n comms: () => FileComms,\n touchIntervalProp: () => number | undefined,\n onGone: (errorText: string) => void,\n) {\n const settings = inject<VuetifyInputsSettings>(vuetifyInputsSettingsKey, {});\n const touchIntervalHandle = ref<number | null>(null);\n\n function clearTouchInterval() {\n if (touchIntervalHandle.value) window.clearInterval(touchIntervalHandle.value);\n }\n\n function setupTouchInterval() {\n clearTouchInterval();\n const interval = touchIntervalProp() ?? settings.defaultTouchInterval ?? 60_000;\n touchIntervalHandle.value = window.setInterval(() => {\n if (value.value) {\n comms()\n .touch(value.value)\n .catch((err) => {\n if (err instanceof FileGoneError) onGone(err.errorText);\n });\n }\n }, interval);\n }\n\n onBeforeUnmount(() => clearTouchInterval());\n watch(value, (newValue) => (newValue ? setupTouchInterval() : clearTouchInterval()));\n\n return { setupTouchInterval, clearTouchInterval };\n}\n\n/**\n * Reports a {@link FileGoneError}'s message on `control`, where one is bound. Kept outside the component's own\n * script so the write to `control.errors` isn't seen as a `.vue` component mutating its own prop — the write\n * goes through `Form.FieldBase`'s own setter, the same way `useInputBase`'s `touched` does.\n */\nexport function setFileGoneError(control: Form.FieldBase | undefined, errorText: string) {\n if (control) control.errors = [new ValidationErrorRenderContent(errorText)];\n}\n","<template>\n <div\n v-if=\"actionsRef.length > 0\"\n class=\"text-end df-actions\"\n :class=\"{\n 'button-group': showAsGroup === 'grouped' || showAsGroup === 'grouped-no-borders',\n 'with-border': showAsGroup === 'grouped',\n }\"\n >\n <v-btn\n v-for=\"(action, idx) in actionsWithBreakpoint\"\n :key=\"idx\"\n :variant=\"action.renderAs === ActionDisplayStyle.BUTTON ? 'tonal' : 'text'\"\n :color=\"defaultActionColor(action)\"\n :disabled=\"!action.action.effectiveEnabled || action.action.busy\"\n :loading=\"action.action.busy\"\n :elevation=\"0\"\n :size=\"buttonSize\"\n :density=\"buttonDensity\"\n :class=\"{\n 'd-none': action.action.visibility === DisplayMode.HIDDEN,\n invisible: action.action.visibility === DisplayMode.INVISIBLE,\n }\"\n v-bind=\"action.passthroughAttrs\"\n @click.stop=\"(event: MouseEvent) => action.action.execute(event)\"\n >\n <cached-icon v-if=\"action.icon\" :name=\"action.icon\" />\n <span v-if=\"action.icon && action.label\" style=\"width: 0.5rem\" />\n <span v-if=\"action.label\">{{ action.label }}</span>\n </v-btn>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { DisplayMode } from '@dynamicforms/vue-forms';\nimport { computed, unref } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfActionsProps } from './dynamicforms-component-props';\nimport { ActionDisplayStyle, ActionRenderOptions, getRenderOptionsForBreakpoint, useBreakpoint } from './helpers';\n\nconst props = withDefaults(defineProps<DfActionsProps>(), {\n buttonSize: 'default',\n buttonDensity: 'default',\n showAsGroup: 'no',\n});\n\nconst breakpoint = useBreakpoint();\nconst actionsRef = computed(() => unref(props.actions).filter((action) => action.visibility !== DisplayMode.SUPPRESS));\n// What each button draws is read off the action's value rather than through the accessors this library's `Action`\n// adds over it, so an action declared as a `@dynamicforms/vue-forms` one - which declares none of them - is drawn\n// as well. The spread is that value resolved at the current breakpoint.\nconst actionsWithBreakpoint = computed(() =>\n actionsRef.value.map((action) => ({\n action,\n ...getRenderOptionsForBreakpoint(action.value, breakpoint.value),\n })),\n);\n\nfunction defaultActionColor(options: ActionRenderOptions): string | undefined {\n if (options.defaultConfirm) return 'primary';\n if (options.defaultReject) return 'secondary';\n return undefined;\n}\n</script>\n\n<style>\n.df-actions.button-group {\n border-radius: 0.5em;\n /* the following two make the container fit the small buttons. without them there would be a top margin */\n line-height: 0;\n height: fit-content;\n}\n.df-actions.button-group .v-btn {\n border: none;\n border-radius: 0;\n margin: 0 !important;\n padding: 0 0.25em;\n}\n.df-actions.button-group .v-btn:first-child {\n border-start-start-radius: 0.5em;\n border-end-start-radius: 0.5em;\n}\n.df-actions.button-group .v-btn:last-child {\n border-start-end-radius: 0.5em;\n border-end-end-radius: 0.5em;\n}\n.df-actions.button-group.with-border {\n border: 0.1em solid currentColor;\n}\n.df-actions.button-group.with-border .v-btn:not(:first-child) {\n border-inline-start: 0.1em solid currentColor;\n}\n.df-actions .v-btn:not(:first-child) {\n margin-left: 0.5em;\n}\n</style>\n","<template>\n <div\n v-if=\"actionsRef.length > 0\"\n class=\"text-end df-actions\"\n :class=\"{\n 'button-group': showAsGroup === 'grouped' || showAsGroup === 'grouped-no-borders',\n 'with-border': showAsGroup === 'grouped',\n }\"\n >\n <v-btn\n v-for=\"(action, idx) in actionsWithBreakpoint\"\n :key=\"idx\"\n :variant=\"action.renderAs === ActionDisplayStyle.BUTTON ? 'tonal' : 'text'\"\n :color=\"defaultActionColor(action)\"\n :disabled=\"!action.action.effectiveEnabled || action.action.busy\"\n :loading=\"action.action.busy\"\n :elevation=\"0\"\n :size=\"buttonSize\"\n :density=\"buttonDensity\"\n :class=\"{\n 'd-none': action.action.visibility === DisplayMode.HIDDEN,\n invisible: action.action.visibility === DisplayMode.INVISIBLE,\n }\"\n v-bind=\"action.passthroughAttrs\"\n @click.stop=\"(event: MouseEvent) => action.action.execute(event)\"\n >\n <cached-icon v-if=\"action.icon\" :name=\"action.icon\" />\n <span v-if=\"action.icon && action.label\" style=\"width: 0.5rem\" />\n <span v-if=\"action.label\">{{ action.label }}</span>\n </v-btn>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { DisplayMode } from '@dynamicforms/vue-forms';\nimport { computed, unref } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfActionsProps } from './dynamicforms-component-props';\nimport { ActionDisplayStyle, ActionRenderOptions, getRenderOptionsForBreakpoint, useBreakpoint } from './helpers';\n\nconst props = withDefaults(defineProps<DfActionsProps>(), {\n buttonSize: 'default',\n buttonDensity: 'default',\n showAsGroup: 'no',\n});\n\nconst breakpoint = useBreakpoint();\nconst actionsRef = computed(() => unref(props.actions).filter((action) => action.visibility !== DisplayMode.SUPPRESS));\n// What each button draws is read off the action's value rather than through the accessors this library's `Action`\n// adds over it, so an action declared as a `@dynamicforms/vue-forms` one - which declares none of them - is drawn\n// as well. The spread is that value resolved at the current breakpoint.\nconst actionsWithBreakpoint = computed(() =>\n actionsRef.value.map((action) => ({\n action,\n ...getRenderOptionsForBreakpoint(action.value, breakpoint.value),\n })),\n);\n\nfunction defaultActionColor(options: ActionRenderOptions): string | undefined {\n if (options.defaultConfirm) return 'primary';\n if (options.defaultReject) return 'secondary';\n return undefined;\n}\n</script>\n\n<style>\n.df-actions.button-group {\n border-radius: 0.5em;\n /* the following two make the container fit the small buttons. without them there would be a top margin */\n line-height: 0;\n height: fit-content;\n}\n.df-actions.button-group .v-btn {\n border: none;\n border-radius: 0;\n margin: 0 !important;\n padding: 0 0.25em;\n}\n.df-actions.button-group .v-btn:first-child {\n border-start-start-radius: 0.5em;\n border-end-start-radius: 0.5em;\n}\n.df-actions.button-group .v-btn:last-child {\n border-start-end-radius: 0.5em;\n border-end-end-radius: 0.5em;\n}\n.df-actions.button-group.with-border {\n border: 0.1em solid currentColor;\n}\n.df-actions.button-group.with-border .v-btn:not(:first-child) {\n border-inline-start: 0.1em solid currentColor;\n}\n.df-actions .v-btn:not(:first-child) {\n margin-left: 0.5em;\n}\n</style>\n","<template>\n <v-checkbox\n v-if=\"isRendered\"\n v-model=\"boolValue\"\n density=\"compact\"\n :class=\"[densityClass, visibilityClass]\"\n :indeterminate=\"indeterminate\"\n :false-value=\"false\"\n :true-value=\"true\"\n v-bind=\"vuetifyBindings as any\"\n @change=\"change\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :allow-wrap=\"true\" :data=\"labelData as any\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"showErrors\" /></template>\n </v-checkbox>\n</template>\n\n<script setup lang=\"ts\">\nimport { clone } from 'lodash-es';\nimport { computed } from 'vue';\n\nimport { DfCheckboxProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfCheckboxProps>(), { ...defaultBaseProps, allowNull: false });\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, showErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\n\nconst indeterminate = computed(() => props.allowNull && value.value == null);\n\nconst boolValue = computed({\n get(): any {\n return value.value;\n },\n set() {},\n});\n\nfunction change() {\n const oldVal = clone(value.value);\n if (oldVal === true) {\n value.value = props.allowNull ? null : false;\n } else {\n value.value = oldVal === false;\n }\n}\n</script>\n","<template>\n <v-checkbox\n v-if=\"isRendered\"\n v-model=\"boolValue\"\n density=\"compact\"\n :class=\"[densityClass, visibilityClass]\"\n :indeterminate=\"indeterminate\"\n :false-value=\"false\"\n :true-value=\"true\"\n v-bind=\"vuetifyBindings as any\"\n @change=\"change\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :allow-wrap=\"true\" :data=\"labelData as any\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"showErrors\" /></template>\n </v-checkbox>\n</template>\n\n<script setup lang=\"ts\">\nimport { clone } from 'lodash-es';\nimport { computed } from 'vue';\n\nimport { DfCheckboxProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfCheckboxProps>(), { ...defaultBaseProps, allowNull: false });\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, showErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\n\nconst indeterminate = computed(() => props.allowNull && value.value == null);\n\nconst boolValue = computed({\n get(): any {\n return value.value;\n },\n set() {},\n});\n\nfunction change() {\n const oldVal = clone(value.value);\n if (oldVal === true) {\n value.value = props.allowNull ? null : false;\n } else {\n value.value = oldVal === false;\n }\n}\n</script>\n","<template>\n <v-text-field\n v-if=\"isRendered\"\n v-model=\"value\"\n :class=\"[densityClass, visibilityClass]\"\n :clearable=\"allowNull\"\n type=\"text\"\n :rules=\"rules\"\n v-bind=\"vuetifyBindings\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"showErrors\" /></template>\n <template #prepend-inner>\n <div\n style=\"width: 24px; height: 24px; border-radius: 4px; border: 1px solid #ccc\"\n :style=\"{ backgroundColor: value }\"\n />\n </template>\n <template #default>\n <v-menu v-model=\"dropdownShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-color-picker v-model=\"value\" mode=\"hexa\" />\n </v-menu>\n </template>\n </v-text-field>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue';\n\nimport { DfColorProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, translatableStrings, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfColorProps>(), { ...defaultBaseProps, allowNull: false });\n\ninterface Emits extends BaseEmits {}\n\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, showErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\nconst dropdownShown = ref(false);\n\nconst rules = computed<((val: string) => boolean | string)[]>(() => [\n (val: string) => {\n if (props.control) return true; // if there's a form field, we expect there to be a validator\n if (!val && props.allowNull) return true; // allowed empty values are also not a problem\n\n const regex = /^#?([a-fA-F0-9]{3}|[a-fA-F0-9]{4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/;\n return regex.test(val) ? true : translatableStrings.InvalidHexColor;\n },\n]);\n</script>\n","<template>\n <v-text-field\n v-if=\"isRendered\"\n v-model=\"value\"\n :class=\"[densityClass, visibilityClass]\"\n :clearable=\"allowNull\"\n type=\"text\"\n :rules=\"rules\"\n v-bind=\"vuetifyBindings\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"showErrors\" /></template>\n <template #prepend-inner>\n <div\n style=\"width: 24px; height: 24px; border-radius: 4px; border: 1px solid #ccc\"\n :style=\"{ backgroundColor: value }\"\n />\n </template>\n <template #default>\n <v-menu v-model=\"dropdownShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-color-picker v-model=\"value\" mode=\"hexa\" />\n </v-menu>\n </template>\n </v-text-field>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue';\n\nimport { DfColorProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, translatableStrings, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfColorProps>(), { ...defaultBaseProps, allowNull: false });\n\ninterface Emits extends BaseEmits {}\n\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, showErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\nconst dropdownShown = ref(false);\n\nconst rules = computed<((val: string) => boolean | string)[]>(() => [\n (val: string) => {\n if (props.control) return true; // if there's a form field, we expect there to be a validator\n if (!val && props.allowNull) return true; // allowed empty values are also not a problem\n\n const regex = /^#?([a-fA-F0-9]{3}|[a-fA-F0-9]{4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/;\n return regex.test(val) ? true : translatableStrings.InvalidHexColor;\n },\n]);\n</script>\n","<template>\n <input-base\n v-bind=\"props\"\n :class=\"densityClass\"\n :clearable=\"clearable\"\n @click:clear=\"value = null\"\n @blur=\"touched = true\"\n >\n <template #default=\"slotProps\">\n <div\n :class=\"[\n 'd-flex',\n 'w-100',\n ['plain', 'underlined'].includes(vuetifyBindings.variant) ? undefined : 'ml-4',\n 'df-input-wrapper',\n density,\n ]\"\n >\n <v-text-field\n v-if=\"['date', 'datetime'].includes(inputType)\"\n v-model=\"dateFormatted\"\n style=\"flex-grow: 4\"\n density=\"compact\"\n variant=\"plain\"\n :clearable=\"false\"\n :hide-details=\"true\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"`${vuetifyBindings.name}-date`\"\n :placeholder=\"vuetifyBindings.placeholder\"\n v-bind=\"passthroughAttrs\"\n @click=\"dropdown = 'date'\"\n @keydown.space=\"dropdown = 'date'\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template #default>\n <v-menu v-model=\"dateMenuShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-confirm-edit v-model=\"valueAsDate\" @cancel=\"dropdown = ''\" @save=\"dropdown = ''\">\n <template #default=\"{ model: proxyModel, actions }\">\n <v-date-picker\n v-model=\"proxyModel.value\"\n :hide-header=\"true\"\n :first-day-of-week=\"firstDayOfWeek\"\n :show-adjacent-months=\"true\"\n :show-week=\"true\"\n >\n <template #actions><component :is=\"actions\" /></template>\n </v-date-picker>\n </template>\n </v-confirm-edit>\n </v-menu>\n </template>\n </v-text-field>\n\n <v-text-field\n v-if=\"['time', 'datetime'].includes(inputType)\"\n v-model=\"timeFormatted\"\n style=\"flex-grow: 3\"\n density=\"compact\"\n variant=\"plain\"\n :clearable=\"false\"\n :hide-details=\"true\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"`${vuetifyBindings.name}-time`\"\n :placeholder=\"inputType === 'time' ? vuetifyBindings.placeholder : undefined\"\n v-bind=\"passthroughAttrs\"\n @click=\"dropdown = 'time'\"\n @keydown.space=\"dropdown = 'time'\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template #default>\n <v-menu v-model=\"timeMenuShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-confirm-edit v-model=\"valueAsTimeString\" @cancel=\"dropdown = ''\" @save=\"dropdown = ''\">\n <template #default=\"{ model: proxyModel, actions }\">\n <v-time-picker v-model=\"proxyModel.value\" :hide-header=\"true\" format=\"24hr\">\n <template #actions><component :is=\"actions\" /></template>\n </v-time-picker>\n </template>\n </v-confirm-edit>\n </v-menu>\n </template>\n </v-text-field>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { format, parse } from 'date-fns';\nimport { toNumber, isNaN } from 'lodash-es';\nimport { ref, computed, watch, toRefs, unref } from 'vue';\n\nimport { DfDateTimeProps } from './dynamicforms-component-props';\nimport { BaseEmits, DateTimeLocaleConfig, defaultBaseProps, InputBase, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfDateTimeProps>(), {\n ...defaultBaseProps,\n inputType: 'datetime',\n displayFormatDate: 'P',\n displayFormatTime: 'p',\n});\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst currentLocale = computed(() => props.locale ?? unref(DateTimeLocaleConfig.dateTimeLocale));\nconst firstDayOfWeek = computed(() => currentLocale.value.options?.weekStartsOn ?? 1);\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase<string | null>(props, emits);\nconst { inputType, displayFormatDate, displayFormatTime } = toRefs(props);\n\nconst dropdown = ref('');\nconst dateMenuShown = computed({\n get() {\n return unref(dropdown) === 'date';\n },\n set(newValue: boolean) {\n dropdown.value = newValue ? 'date' : '';\n },\n});\nconst timeMenuShown = computed({\n get() {\n return unref(dropdown) === 'time';\n },\n set(newValue: boolean) {\n dropdown.value = newValue ? 'time' : '';\n },\n});\n\nconst formatNaive = (val: Date) => `${format(val, 'yyyy-MM-dd')}T${format(val, 'HH:mm')}:00`;\n\nconst valueISOFull = ref<string | null>(null);\nfunction setValueISOFull(newISOValue: string | null, dateOrTimeIdx: number) {\n if (newISOValue == null) {\n valueISOFull.value = null;\n } else if (dateOrTimeIdx === -1) {\n // setting valueISOFull from value\n if (unref(inputType) === 'time') {\n valueISOFull.value = formatNaive(new Date());\n setValueISOFull(`T${newISOValue}`, 1);\n } else {\n const val = formatNaive(new Date(newISOValue));\n setValueISOFull(val, 0);\n setValueISOFull(val, 1);\n }\n } else {\n if (valueISOFull.value == null) valueISOFull.value = formatNaive(new Date());\n const vif = valueISOFull.value.split(/[TZ]/g);\n const nv = newISOValue!.split(/[TZ]/g);\n vif[dateOrTimeIdx] = nv[dateOrTimeIdx];\n valueISOFull.value = formatNaive(new Date(`${vif[0]}T${vif[1].split('.')[0]}`));\n\n if (unref(inputType) === 'date') value.value = vif[0];\n else if (unref(inputType) === 'time') value.value = vif[1];\n else value.value = unref(valueISOFull) + format(new Date(), 'XXX');\n }\n}\nwatch(value, (newValue: string | null) => setValueISOFull(newValue, -1), { immediate: true });\n\nconst valueAsDate = computed({\n get() {\n const uValue = unref(valueISOFull);\n if (uValue == null) return null;\n const res = new Date(uValue);\n return !Number.isNaN(res.getTime()) ? res : null;\n },\n set(newValue: Date) {\n setValueISOFull(formatNaive(newValue), 0);\n },\n});\n\nconst valueAsTimeString = computed({\n get() {\n const val = unref(valueISOFull);\n if (val == null) return '';\n const vif = val.split(/[TZ]/g);\n return vif[1].split('.')[0];\n },\n set(newValue: string) {\n setValueISOFull(`T${newValue}`, 1);\n },\n});\n\nconst dateFormatted = computed({\n get() {\n const vad = unref(valueAsDate);\n if (vad == null) return '';\n return format(vad, unref(displayFormatDate), { locale: currentLocale.value });\n },\n set(newValue: string) {\n try {\n const d = parse(newValue, unref(displayFormatDate), new Date(), { locale: currentLocale.value });\n setValueISOFull(formatNaive(d), 0);\n } catch (err) {\n console.error(err);\n }\n },\n});\n\nconst timeFormatted = computed({\n get() {\n const vad = unref(valueAsDate);\n if (vad == null) return '';\n return format(vad, unref(displayFormatTime), { locale: currentLocale.value });\n },\n set(newValue: string) {\n const d = newValue.match(/(\\d+):(\\d+)\\s?([a-zA-Z]+)?/);\n if (d == null) return;\n let hour = toNumber(d[1]);\n const minute = toNumber(d[2]);\n if (isNaN(hour) || isNaN(minute)) return;\n if (d[3] && d[3].toLowerCase() === 'pm' && hour < 13) hour += 12;\n setValueISOFull(`T${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:00`, 1);\n },\n});\n</script>\n","<template>\n <input-base\n v-bind=\"props\"\n :class=\"densityClass\"\n :clearable=\"clearable\"\n @click:clear=\"value = null\"\n @blur=\"touched = true\"\n >\n <template #default=\"slotProps\">\n <div\n :class=\"[\n 'd-flex',\n 'w-100',\n ['plain', 'underlined'].includes(vuetifyBindings.variant) ? undefined : 'ml-4',\n 'df-input-wrapper',\n density,\n ]\"\n >\n <v-text-field\n v-if=\"['date', 'datetime'].includes(inputType)\"\n v-model=\"dateFormatted\"\n style=\"flex-grow: 4\"\n density=\"compact\"\n variant=\"plain\"\n :clearable=\"false\"\n :hide-details=\"true\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"`${vuetifyBindings.name}-date`\"\n :placeholder=\"vuetifyBindings.placeholder\"\n v-bind=\"passthroughAttrs\"\n @click=\"dropdown = 'date'\"\n @keydown.space=\"dropdown = 'date'\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template #default>\n <v-menu v-model=\"dateMenuShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-confirm-edit v-model=\"valueAsDate\" @cancel=\"dropdown = ''\" @save=\"dropdown = ''\">\n <template #default=\"{ model: proxyModel, actions }\">\n <v-date-picker\n v-model=\"proxyModel.value\"\n :hide-header=\"true\"\n :first-day-of-week=\"firstDayOfWeek\"\n :show-adjacent-months=\"true\"\n :show-week=\"true\"\n >\n <template #actions><component :is=\"actions\" /></template>\n </v-date-picker>\n </template>\n </v-confirm-edit>\n </v-menu>\n </template>\n </v-text-field>\n\n <v-text-field\n v-if=\"['time', 'datetime'].includes(inputType)\"\n v-model=\"timeFormatted\"\n style=\"flex-grow: 3\"\n density=\"compact\"\n variant=\"plain\"\n :clearable=\"false\"\n :hide-details=\"true\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"`${vuetifyBindings.name}-time`\"\n :placeholder=\"inputType === 'time' ? vuetifyBindings.placeholder : undefined\"\n v-bind=\"passthroughAttrs\"\n @click=\"dropdown = 'time'\"\n @keydown.space=\"dropdown = 'time'\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template #default>\n <v-menu v-model=\"timeMenuShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-confirm-edit v-model=\"valueAsTimeString\" @cancel=\"dropdown = ''\" @save=\"dropdown = ''\">\n <template #default=\"{ model: proxyModel, actions }\">\n <v-time-picker v-model=\"proxyModel.value\" :hide-header=\"true\" format=\"24hr\">\n <template #actions><component :is=\"actions\" /></template>\n </v-time-picker>\n </template>\n </v-confirm-edit>\n </v-menu>\n </template>\n </v-text-field>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { format, parse } from 'date-fns';\nimport { toNumber, isNaN } from 'lodash-es';\nimport { ref, computed, watch, toRefs, unref } from 'vue';\n\nimport { DfDateTimeProps } from './dynamicforms-component-props';\nimport { BaseEmits, DateTimeLocaleConfig, defaultBaseProps, InputBase, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfDateTimeProps>(), {\n ...defaultBaseProps,\n inputType: 'datetime',\n displayFormatDate: 'P',\n displayFormatTime: 'p',\n});\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst currentLocale = computed(() => props.locale ?? unref(DateTimeLocaleConfig.dateTimeLocale));\nconst firstDayOfWeek = computed(() => currentLocale.value.options?.weekStartsOn ?? 1);\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase<string | null>(props, emits);\nconst { inputType, displayFormatDate, displayFormatTime } = toRefs(props);\n\nconst dropdown = ref('');\nconst dateMenuShown = computed({\n get() {\n return unref(dropdown) === 'date';\n },\n set(newValue: boolean) {\n dropdown.value = newValue ? 'date' : '';\n },\n});\nconst timeMenuShown = computed({\n get() {\n return unref(dropdown) === 'time';\n },\n set(newValue: boolean) {\n dropdown.value = newValue ? 'time' : '';\n },\n});\n\nconst formatNaive = (val: Date) => `${format(val, 'yyyy-MM-dd')}T${format(val, 'HH:mm')}:00`;\n\nconst valueISOFull = ref<string | null>(null);\nfunction setValueISOFull(newISOValue: string | null, dateOrTimeIdx: number) {\n if (newISOValue == null) {\n valueISOFull.value = null;\n } else if (dateOrTimeIdx === -1) {\n // setting valueISOFull from value\n if (unref(inputType) === 'time') {\n valueISOFull.value = formatNaive(new Date());\n setValueISOFull(`T${newISOValue}`, 1);\n } else {\n const val = formatNaive(new Date(newISOValue));\n setValueISOFull(val, 0);\n setValueISOFull(val, 1);\n }\n } else {\n if (valueISOFull.value == null) valueISOFull.value = formatNaive(new Date());\n const vif = valueISOFull.value.split(/[TZ]/g);\n const nv = newISOValue!.split(/[TZ]/g);\n vif[dateOrTimeIdx] = nv[dateOrTimeIdx];\n valueISOFull.value = formatNaive(new Date(`${vif[0]}T${vif[1].split('.')[0]}`));\n\n if (unref(inputType) === 'date') value.value = vif[0];\n else if (unref(inputType) === 'time') value.value = vif[1];\n else value.value = unref(valueISOFull) + format(new Date(), 'XXX');\n }\n}\nwatch(value, (newValue: string | null) => setValueISOFull(newValue, -1), { immediate: true });\n\nconst valueAsDate = computed({\n get() {\n const uValue = unref(valueISOFull);\n if (uValue == null) return null;\n const res = new Date(uValue);\n return !Number.isNaN(res.getTime()) ? res : null;\n },\n set(newValue: Date) {\n setValueISOFull(formatNaive(newValue), 0);\n },\n});\n\nconst valueAsTimeString = computed({\n get() {\n const val = unref(valueISOFull);\n if (val == null) return '';\n const vif = val.split(/[TZ]/g);\n return vif[1].split('.')[0];\n },\n set(newValue: string) {\n setValueISOFull(`T${newValue}`, 1);\n },\n});\n\nconst dateFormatted = computed({\n get() {\n const vad = unref(valueAsDate);\n if (vad == null) return '';\n return format(vad, unref(displayFormatDate), { locale: currentLocale.value });\n },\n set(newValue: string) {\n try {\n const d = parse(newValue, unref(displayFormatDate), new Date(), { locale: currentLocale.value });\n setValueISOFull(formatNaive(d), 0);\n } catch (err) {\n console.error(err);\n }\n },\n});\n\nconst timeFormatted = computed({\n get() {\n const vad = unref(valueAsDate);\n if (vad == null) return '';\n return format(vad, unref(displayFormatTime), { locale: currentLocale.value });\n },\n set(newValue: string) {\n const d = newValue.match(/(\\d+):(\\d+)\\s?([a-zA-Z]+)?/);\n if (d == null) return;\n let hour = toNumber(d[1]);\n const minute = toNumber(d[2]);\n if (isNaN(hour) || isNaN(minute)) return;\n if (d[3] && d[3].toLowerCase() === 'pm' && hour < 13) hour += 12;\n setValueISOFull(`T${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:00`, 1);\n },\n});\n</script>\n","<template>\n <input-base\n v-bind=\"{ ...props, loading } as any\"\n :class=\"densityClass\"\n clearable\n @click:clear=\"removeFile\"\n @blur=\"touched = true\"\n >\n <template #prepend-inner><cached-icon name=\"mdi-paperclip\" /></template>\n <template #loader>\n <v-progress-linear\n v-if=\"currentFile && progress < 100\"\n :model-value=\"progress\"\n :indeterminate=\"progress === -1\"\n />\n </template>\n <template #default=\"slotProps\">\n <div class=\"d-flex w-100 position-relative df-input-wrapper\" :class=\"density\">\n <v-file-input\n v-model=\"selectedFile\"\n :label=\"fileLabel\"\n density=\"compact\"\n variant=\"plain\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"vuetifyBindings.name\"\n :hide-details=\"true\"\n :show-size=\"true\"\n :multiple=\"false\"\n :style=\"currentFile && progress < 100 ? 'visibility: hidden' : ''\"\n :clearable=\"false\"\n v-bind=\"passthroughAttrs\"\n prepend-icon=\"\"\n @update:model-value=\"handleFileChange\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template v-if=\"canDownload\" #append-inner>\n <button\n type=\"button\"\n class=\"df-file-download-btn\"\n :title=\"t.FileDownload\"\n :aria-label=\"t.FileDownload\"\n @click.stop.prevent=\"downloadFile\"\n >\n <cached-icon name=\"mdi-download\" />\n </button>\n </template>\n </v-file-input>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfFileProps } from './dynamicforms-component-props';\nimport {\n BaseEmits,\n defaultBaseProps,\n InputBase,\n setFileGoneError,\n translatableStrings,\n useFileTouchKeepAlive,\n useInputBase,\n} from './helpers';\n\nconst props = withDefaults(defineProps<DfFileProps>(), defaultBaseProps);\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase(props, emits);\nconst t = translatableStrings;\n\n// State\nconst currentFile = ref<File | null>(null);\nconst progress = ref(0);\nconst fileInputKey = ref(Math.round(Math.random() * 1000));\nconst selectedFile = ref<File | null>();\nconst loading = computed(() => currentFile.value && progress.value < 100);\n\nconst fileLabel = computed(() => {\n if (!selectedFile.value && value.value) {\n return value.value;\n }\n return '';\n});\n\nconst canDownload = computed(() => !selectedFile.value && !!value.value && !!props.comms.getDownloadUrl);\n\nasync function downloadFile() {\n if (!value.value || !props.comms.getDownloadUrl) return;\n\n const url = await props.comms.getDownloadUrl(value.value);\n const link = document.createElement('a');\n link.href = url;\n link.download = '';\n link.rel = 'noopener';\n link.click();\n}\n\nfunction resetFileState() {\n value.value = null;\n progress.value = 0;\n fileInputKey.value = Math.round(Math.random() * 1000);\n currentFile.value = null;\n selectedFile.value = null;\n clearTouchInterval();\n}\n\nfunction handleFileGone(errorText: string) {\n resetFileState();\n setFileGoneError(props.control, errorText);\n}\n\nconst { setupTouchInterval, clearTouchInterval } = useFileTouchKeepAlive(\n value,\n () => props.comms,\n () => props.touchInterval,\n handleFileGone,\n);\n\nasync function removeFile() {\n if (value.value) {\n await props.comms.delete(value.value);\n }\n\n resetFileState();\n}\n\nasync function upload(file: File) {\n progress.value = -1;\n currentFile.value = file;\n\n try {\n value.value = await props.comms.upload(file, (loaded: number, total: number) => {\n progress.value = Math.round((loaded * 100) / total);\n });\n progress.value = 100;\n setupTouchInterval();\n } catch (err) {\n progress.value = 0;\n currentFile.value = null;\n fileInputKey.value = Math.round(Math.random() * 1000);\n selectedFile.value = null;\n throw err;\n }\n}\n\nfunction handleFileChange(file: File | File[]): any {\n if (file) {\n if (Array.isArray(file)) {\n console.error('Uploading multiple files not supported right now');\n } else {\n upload(file);\n }\n }\n}\n</script>\n\n<style>\n.df-file-download-btn {\n display: inline-flex;\n align-items: center;\n cursor: pointer;\n opacity: 0.7;\n}\n.df-file-download-btn:hover {\n opacity: 1;\n}\n\n.df-input-wrapper .v-file-input--dragging {\n outline: 2px dashed rgb(var(--v-theme-primary));\n outline-offset: -2px;\n background-color: rgba(var(--v-theme-primary), 0.08);\n}\n</style>\n","<template>\n <input-base\n v-bind=\"{ ...props, loading } as any\"\n :class=\"densityClass\"\n clearable\n @click:clear=\"removeFile\"\n @blur=\"touched = true\"\n >\n <template #prepend-inner><cached-icon name=\"mdi-paperclip\" /></template>\n <template #loader>\n <v-progress-linear\n v-if=\"currentFile && progress < 100\"\n :model-value=\"progress\"\n :indeterminate=\"progress === -1\"\n />\n </template>\n <template #default=\"slotProps\">\n <div class=\"d-flex w-100 position-relative df-input-wrapper\" :class=\"density\">\n <v-file-input\n v-model=\"selectedFile\"\n :label=\"fileLabel\"\n density=\"compact\"\n variant=\"plain\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"vuetifyBindings.name\"\n :hide-details=\"true\"\n :show-size=\"true\"\n :multiple=\"false\"\n :style=\"currentFile && progress < 100 ? 'visibility: hidden' : ''\"\n :clearable=\"false\"\n v-bind=\"passthroughAttrs\"\n prepend-icon=\"\"\n @update:model-value=\"handleFileChange\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template v-if=\"canDownload\" #append-inner>\n <button\n type=\"button\"\n class=\"df-file-download-btn\"\n :title=\"t.FileDownload\"\n :aria-label=\"t.FileDownload\"\n @click.stop.prevent=\"downloadFile\"\n >\n <cached-icon name=\"mdi-download\" />\n </button>\n </template>\n </v-file-input>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfFileProps } from './dynamicforms-component-props';\nimport {\n BaseEmits,\n defaultBaseProps,\n InputBase,\n setFileGoneError,\n translatableStrings,\n useFileTouchKeepAlive,\n useInputBase,\n} from './helpers';\n\nconst props = withDefaults(defineProps<DfFileProps>(), defaultBaseProps);\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase(props, emits);\nconst t = translatableStrings;\n\n// State\nconst currentFile = ref<File | null>(null);\nconst progress = ref(0);\nconst fileInputKey = ref(Math.round(Math.random() * 1000));\nconst selectedFile = ref<File | null>();\nconst loading = computed(() => currentFile.value && progress.value < 100);\n\nconst fileLabel = computed(() => {\n if (!selectedFile.value && value.value) {\n return value.value;\n }\n return '';\n});\n\nconst canDownload = computed(() => !selectedFile.value && !!value.value && !!props.comms.getDownloadUrl);\n\nasync function downloadFile() {\n if (!value.value || !props.comms.getDownloadUrl) return;\n\n const url = await props.comms.getDownloadUrl(value.value);\n const link = document.createElement('a');\n link.href = url;\n link.download = '';\n link.rel = 'noopener';\n link.click();\n}\n\nfunction resetFileState() {\n value.value = null;\n progress.value = 0;\n fileInputKey.value = Math.round(Math.random() * 1000);\n currentFile.value = null;\n selectedFile.value = null;\n clearTouchInterval();\n}\n\nfunction handleFileGone(errorText: string) {\n resetFileState();\n setFileGoneError(props.control, errorText);\n}\n\nconst { setupTouchInterval, clearTouchInterval } = useFileTouchKeepAlive(\n value,\n () => props.comms,\n () => props.touchInterval,\n handleFileGone,\n);\n\nasync function removeFile() {\n if (value.value) {\n await props.comms.delete(value.value);\n }\n\n resetFileState();\n}\n\nasync function upload(file: File) {\n progress.value = -1;\n currentFile.value = file;\n\n try {\n value.value = await props.comms.upload(file, (loaded: number, total: number) => {\n progress.value = Math.round((loaded * 100) / total);\n });\n progress.value = 100;\n setupTouchInterval();\n } catch (err) {\n progress.value = 0;\n currentFile.value = null;\n fileInputKey.value = Math.round(Math.random() * 1000);\n selectedFile.value = null;\n throw err;\n }\n}\n\nfunction handleFileChange(file: File | File[]): any {\n if (file) {\n if (Array.isArray(file)) {\n console.error('Uploading multiple files not supported right now');\n } else {\n upload(file);\n }\n }\n}\n</script>\n\n<style>\n.df-file-download-btn {\n display: inline-flex;\n align-items: center;\n cursor: pointer;\n opacity: 0.7;\n}\n.df-file-download-btn:hover {\n opacity: 1;\n}\n\n.df-input-wrapper .v-file-input--dragging {\n outline: 2px dashed rgb(var(--v-theme-primary));\n outline-offset: -2px;\n background-color: rgba(var(--v-theme-primary), 0.08);\n}\n</style>\n","<template>\n <input-base\n v-bind=\"{ ...props, loading } as any\"\n class=\"df-image-field\"\n :class=\"densityClass\"\n clearable\n @click:clear=\"removeFile\"\n @blur=\"touched = true\"\n >\n <template #prepend-inner><cached-icon name=\"mdi-image\" /></template>\n <template #loader>\n <v-progress-linear\n v-if=\"currentFile && progress < 100\"\n :model-value=\"progress\"\n :indeterminate=\"progress === -1\"\n />\n </template>\n <template #default=\"slotProps\">\n <!-- click.stop: v-field's own click handler calls preventDefault whenever the click target isn't already\n the focused element, which would silently cancel a <label>'s file-picker default action before it\n can reach the input it targets. -->\n <div\n class=\"d-flex w-100 position-relative df-input-wrapper df-image-wrapper\"\n :class=\"[density, { 'df-image-dragging': isDragging, 'df-image-disabled': isDisabled }]\"\n @dragenter.prevent=\"onDragEnter\"\n @dragover.prevent\n @dragleave.prevent=\"onDragLeave\"\n @drop.prevent=\"onDrop\"\n @click.stop\n >\n <input\n :id=\"fileInputId\"\n ref=\"fileInputRef\"\n type=\"file\"\n accept=\"image/*\"\n class=\"df-image-native-input\"\n :disabled=\"isDisabled\"\n :name=\"vuetifyBindings.name\"\n @change=\"onNativeChange\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n />\n <label v-if=\"previewUrl\" :for=\"fileInputId\" class=\"df-image-preview-label\">\n <v-img\n :src=\"previewUrl\"\n class=\"df-image-preview\"\n :style=\"currentFile && progress < 100 ? 'visibility: hidden' : ''\"\n />\n </label>\n <label v-else :for=\"fileInputId\" class=\"df-image-placeholder\">\n <cached-icon name=\"mdi-tray-arrow-up\" />\n <span>{{ t.ImageDropHint }}</span>\n </label>\n <label v-if=\"previewUrl && !isDisabled\" :for=\"fileInputId\" class=\"df-image-replace-btn\" :title=\"t.ImageReplace\">\n <cached-icon name=\"mdi-pencil\" />\n </label>\n <a\n v-if=\"canDownload\"\n :href=\"value as string\"\n download\n target=\"_blank\"\n rel=\"noopener\"\n class=\"df-image-download-btn\"\n :title=\"t.ImageDownload\"\n :aria-label=\"t.ImageDownload\"\n >\n <cached-icon name=\"mdi-download\" />\n </a>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, useId } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfImageProps } from './dynamicforms-component-props';\nimport {\n BaseEmits,\n defaultBaseProps,\n InputBase,\n setFileGoneError,\n translatableStrings,\n useFileTouchKeepAlive,\n useInputBase,\n} from './helpers';\n\nconst props = withDefaults(defineProps<DfImageProps>(), defaultBaseProps);\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase(props, emits);\nconst t = translatableStrings;\nconst fileInputId = useId();\n\n// State\nconst currentFile = ref<File | null>(null);\nconst progress = ref(0);\nconst objectUrl = ref<string | null>(null);\nconst dragCounter = ref(0);\nconst fileInputRef = ref<HTMLInputElement | null>(null);\n\nconst loading = computed(() => currentFile.value && progress.value < 100);\nconst isDisabled = computed(() => !!(vuetifyBindings.value.disabled || vuetifyBindings.value.readonly));\nconst isDragging = computed(() => dragCounter.value > 0);\nconst previewUrl = computed<string | null>(() => objectUrl.value ?? (value.value ? (value.value as string) : null));\nconst canDownload = computed(() => !!value.value);\n\nfunction revokeObjectUrl() {\n if (objectUrl.value) {\n URL.revokeObjectURL(objectUrl.value);\n objectUrl.value = null;\n }\n}\n\nfunction resetFileState() {\n value.value = null;\n progress.value = 0;\n currentFile.value = null;\n revokeObjectUrl();\n clearTouchInterval();\n}\n\nfunction handleFileGone(errorText: string) {\n resetFileState();\n setFileGoneError(props.control, errorText);\n}\n\nconst { setupTouchInterval, clearTouchInterval } = useFileTouchKeepAlive(\n value,\n () => props.comms,\n () => props.touchInterval,\n handleFileGone,\n);\n\nonBeforeUnmount(() => revokeObjectUrl());\n\nasync function removeFile() {\n if (value.value) {\n await props.comms.delete(value.value);\n }\n\n resetFileState();\n}\n\nasync function upload(file: File) {\n progress.value = -1;\n currentFile.value = file;\n revokeObjectUrl();\n objectUrl.value = URL.createObjectURL(file);\n\n try {\n value.value = await props.comms.upload(file, (loaded: number, total: number) => {\n progress.value = Math.round((loaded * 100) / total);\n });\n progress.value = 100;\n setupTouchInterval();\n } catch (err) {\n progress.value = 0;\n currentFile.value = null;\n revokeObjectUrl();\n throw err;\n }\n}\n\nfunction handleFile(file: File) {\n if (!file.type.startsWith('image/')) {\n console.error('Only image files are supported');\n return;\n }\n upload(file);\n}\n\nfunction onNativeChange(event: Event) {\n const input = event.target as HTMLInputElement;\n const file = input.files?.[0];\n input.value = '';\n if (file) handleFile(file);\n}\n\nfunction onDragEnter() {\n if (isDisabled.value) return;\n dragCounter.value += 1;\n}\nfunction onDragLeave() {\n dragCounter.value = Math.max(0, dragCounter.value - 1);\n}\nfunction onDrop(event: DragEvent) {\n dragCounter.value = 0;\n if (isDisabled.value) return;\n const file = event.dataTransfer?.files?.[0];\n if (file) handleFile(file);\n}\n</script>\n\n<style>\n/* .df-sub-field caps itself at the height of a single-line input; without lifting that cap here, the taller\n image area would keep the field's own layout box small and just paint over whatever follows it on the page. */\n.df-image-field .df-sub-field {\n max-height: revert;\n}\n\n.df-image-wrapper {\n height: 160px;\n border: 1px dashed rgba(128, 128, 128, 0.5);\n border-radius: 4px;\n overflow: hidden;\n}\n.df-image-wrapper.df-image-dragging {\n border-color: rgb(var(--v-theme-primary));\n background-color: rgba(var(--v-theme-primary), 0.08);\n}\n.df-image-wrapper.df-image-disabled .df-image-placeholder,\n.df-image-wrapper.df-image-disabled .df-image-preview-label {\n cursor: not-allowed;\n}\n\n/* Visually hidden but focusable (keyboard-reachable) and clickable via its <label>s. */\n.df-image-native-input {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n opacity: 0;\n}\n.df-image-native-input:focus-visible ~ label {\n outline: 2px solid rgb(var(--v-theme-primary));\n outline-offset: -2px;\n}\n\n.df-image-preview-label,\n.df-image-preview {\n display: block;\n width: 100%;\n height: 100%;\n}\n/* a host page's own typography reset (e.g. margin on bare <img> tags) would otherwise offset v-img's <img> from\n the box it's meant to fill exactly, clipping it against .df-image-wrapper's overflow:hidden */\n.df-image-preview img {\n margin: 0;\n}\n.df-image-preview-label {\n cursor: pointer;\n}\n\n.df-image-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 4px;\n width: 100%;\n height: 100%;\n cursor: pointer;\n color: inherit;\n opacity: 0.7;\n}\n\n.df-image-replace-btn,\n.df-image-download-btn {\n position: absolute;\n top: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n cursor: pointer;\n background-color: rgba(var(--v-theme-surface), 0.9);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n.df-image-replace-btn {\n right: 4px;\n}\n.df-image-download-btn {\n left: 4px;\n color: inherit;\n}\n</style>\n","<template>\n <input-base\n v-bind=\"{ ...props, loading } as any\"\n class=\"df-image-field\"\n :class=\"densityClass\"\n clearable\n @click:clear=\"removeFile\"\n @blur=\"touched = true\"\n >\n <template #prepend-inner><cached-icon name=\"mdi-image\" /></template>\n <template #loader>\n <v-progress-linear\n v-if=\"currentFile && progress < 100\"\n :model-value=\"progress\"\n :indeterminate=\"progress === -1\"\n />\n </template>\n <template #default=\"slotProps\">\n <!-- click.stop: v-field's own click handler calls preventDefault whenever the click target isn't already\n the focused element, which would silently cancel a <label>'s file-picker default action before it\n can reach the input it targets. -->\n <div\n class=\"d-flex w-100 position-relative df-input-wrapper df-image-wrapper\"\n :class=\"[density, { 'df-image-dragging': isDragging, 'df-image-disabled': isDisabled }]\"\n @dragenter.prevent=\"onDragEnter\"\n @dragover.prevent\n @dragleave.prevent=\"onDragLeave\"\n @drop.prevent=\"onDrop\"\n @click.stop\n >\n <input\n :id=\"fileInputId\"\n ref=\"fileInputRef\"\n type=\"file\"\n accept=\"image/*\"\n class=\"df-image-native-input\"\n :disabled=\"isDisabled\"\n :name=\"vuetifyBindings.name\"\n @change=\"onNativeChange\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n />\n <label v-if=\"previewUrl\" :for=\"fileInputId\" class=\"df-image-preview-label\">\n <v-img\n :src=\"previewUrl\"\n class=\"df-image-preview\"\n :style=\"currentFile && progress < 100 ? 'visibility: hidden' : ''\"\n />\n </label>\n <label v-else :for=\"fileInputId\" class=\"df-image-placeholder\">\n <cached-icon name=\"mdi-tray-arrow-up\" />\n <span>{{ t.ImageDropHint }}</span>\n </label>\n <label v-if=\"previewUrl && !isDisabled\" :for=\"fileInputId\" class=\"df-image-replace-btn\" :title=\"t.ImageReplace\">\n <cached-icon name=\"mdi-pencil\" />\n </label>\n <a\n v-if=\"canDownload\"\n :href=\"value as string\"\n download\n target=\"_blank\"\n rel=\"noopener\"\n class=\"df-image-download-btn\"\n :title=\"t.ImageDownload\"\n :aria-label=\"t.ImageDownload\"\n >\n <cached-icon name=\"mdi-download\" />\n </a>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, useId } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfImageProps } from './dynamicforms-component-props';\nimport {\n BaseEmits,\n defaultBaseProps,\n InputBase,\n setFileGoneError,\n translatableStrings,\n useFileTouchKeepAlive,\n useInputBase,\n} from './helpers';\n\nconst props = withDefaults(defineProps<DfImageProps>(), defaultBaseProps);\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase(props, emits);\nconst t = translatableStrings;\nconst fileInputId = useId();\n\n// State\nconst currentFile = ref<File | null>(null);\nconst progress = ref(0);\nconst objectUrl = ref<string | null>(null);\nconst dragCounter = ref(0);\nconst fileInputRef = ref<HTMLInputElement | null>(null);\n\nconst loading = computed(() => currentFile.value && progress.value < 100);\nconst isDisabled = computed(() => !!(vuetifyBindings.value.disabled || vuetifyBindings.value.readonly));\nconst isDragging = computed(() => dragCounter.value > 0);\nconst previewUrl = computed<string | null>(() => objectUrl.value ?? (value.value ? (value.value as string) : null));\nconst canDownload = computed(() => !!value.value);\n\nfunction revokeObjectUrl() {\n if (objectUrl.value) {\n URL.revokeObjectURL(objectUrl.value);\n objectUrl.value = null;\n }\n}\n\nfunction resetFileState() {\n value.value = null;\n progress.value = 0;\n currentFile.value = null;\n revokeObjectUrl();\n clearTouchInterval();\n}\n\nfunction handleFileGone(errorText: string) {\n resetFileState();\n setFileGoneError(props.control, errorText);\n}\n\nconst { setupTouchInterval, clearTouchInterval } = useFileTouchKeepAlive(\n value,\n () => props.comms,\n () => props.touchInterval,\n handleFileGone,\n);\n\nonBeforeUnmount(() => revokeObjectUrl());\n\nasync function removeFile() {\n if (value.value) {\n await props.comms.delete(value.value);\n }\n\n resetFileState();\n}\n\nasync function upload(file: File) {\n progress.value = -1;\n currentFile.value = file;\n revokeObjectUrl();\n objectUrl.value = URL.createObjectURL(file);\n\n try {\n value.value = await props.comms.upload(file, (loaded: number, total: number) => {\n progress.value = Math.round((loaded * 100) / total);\n });\n progress.value = 100;\n setupTouchInterval();\n } catch (err) {\n progress.value = 0;\n currentFile.value = null;\n revokeObjectUrl();\n throw err;\n }\n}\n\nfunction handleFile(file: File) {\n if (!file.type.startsWith('image/')) {\n console.error('Only image files are supported');\n return;\n }\n upload(file);\n}\n\nfunction onNativeChange(event: Event) {\n const input = event.target as HTMLInputElement;\n const file = input.files?.[0];\n input.value = '';\n if (file) handleFile(file);\n}\n\nfunction onDragEnter() {\n if (isDisabled.value) return;\n dragCounter.value += 1;\n}\nfunction onDragLeave() {\n dragCounter.value = Math.max(0, dragCounter.value - 1);\n}\nfunction onDrop(event: DragEvent) {\n dragCounter.value = 0;\n if (isDisabled.value) return;\n const file = event.dataTransfer?.files?.[0];\n if (file) handleFile(file);\n}\n</script>\n\n<style>\n/* .df-sub-field caps itself at the height of a single-line input; without lifting that cap here, the taller\n image area would keep the field's own layout box small and just paint over whatever follows it on the page. */\n.df-image-field .df-sub-field {\n max-height: revert;\n}\n\n.df-image-wrapper {\n height: 160px;\n border: 1px dashed rgba(128, 128, 128, 0.5);\n border-radius: 4px;\n overflow: hidden;\n}\n.df-image-wrapper.df-image-dragging {\n border-color: rgb(var(--v-theme-primary));\n background-color: rgba(var(--v-theme-primary), 0.08);\n}\n.df-image-wrapper.df-image-disabled .df-image-placeholder,\n.df-image-wrapper.df-image-disabled .df-image-preview-label {\n cursor: not-allowed;\n}\n\n/* Visually hidden but focusable (keyboard-reachable) and clickable via its <label>s. */\n.df-image-native-input {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n opacity: 0;\n}\n.df-image-native-input:focus-visible ~ label {\n outline: 2px solid rgb(var(--v-theme-primary));\n outline-offset: -2px;\n}\n\n.df-image-preview-label,\n.df-image-preview {\n display: block;\n width: 100%;\n height: 100%;\n}\n/* a host page's own typography reset (e.g. margin on bare <img> tags) would otherwise offset v-img's <img> from\n the box it's meant to fill exactly, clipping it against .df-image-wrapper's overflow:hidden */\n.df-image-preview img {\n margin: 0;\n}\n.df-image-preview-label {\n cursor: pointer;\n}\n\n.df-image-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 4px;\n width: 100%;\n height: 100%;\n cursor: pointer;\n color: inherit;\n opacity: 0.7;\n}\n\n.df-image-replace-btn,\n.df-image-download-btn {\n position: absolute;\n top: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n cursor: pointer;\n background-color: rgba(var(--v-theme-surface), 0.9);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n.df-image-replace-btn {\n right: 4px;\n}\n.df-image-download-btn {\n left: 4px;\n color: inherit;\n}\n</style>\n","<template>\n <div v-if=\"isRendered\" class=\"df-input-container\" :class=\"[densityClass, visibilityClass]\">\n <v-text-field\n v-if=\"!isNumber\"\n v-model=\"value\"\n :type=\"inputType\"\n v-bind=\"vuetifyBindings as any\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"showErrors\" /></template>\n </v-text-field>\n <v-number-input\n v-else\n v-model=\"value\"\n density=\"compact\"\n control-variant=\"stacked\"\n v-bind=\"{ ...vuetifyBindings, ...numberInputBindings } as any\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"showErrors\" /></template>\n </v-number-input>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, toRefs, unref } from 'vue';\n\nimport { DfInputProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfInputProps>(), {\n ...defaultBaseProps,\n inputType: 'text',\n precision: null,\n step: undefined,\n min: undefined,\n max: undefined,\n});\n\ninterface Emits extends BaseEmits {}\n\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, showErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\nconst { inputType, max, min, precision, step } = toRefs(props);\n\nconst isNumber = computed(() => inputType.value === 'number');\nconst numberInputBindings = computed(() =>\n !isNumber.value ? {} : { min: unref(min), max: unref(max), precision: unref(precision), step: unref(step) },\n);\n</script>\n","<template>\n <div v-if=\"isRendered\" class=\"df-input-container\" :class=\"[densityClass, visibilityClass]\">\n <v-text-field\n v-if=\"!isNumber\"\n v-model=\"value\"\n :type=\"inputType\"\n v-bind=\"vuetifyBindings as any\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"showErrors\" /></template>\n </v-text-field>\n <v-number-input\n v-else\n v-model=\"value\"\n density=\"compact\"\n control-variant=\"stacked\"\n v-bind=\"{ ...vuetifyBindings, ...numberInputBindings } as any\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"showErrors\" /></template>\n </v-number-input>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, toRefs, unref } from 'vue';\n\nimport { DfInputProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfInputProps>(), {\n ...defaultBaseProps,\n inputType: 'text',\n precision: null,\n step: undefined,\n min: undefined,\n max: undefined,\n});\n\ninterface Emits extends BaseEmits {}\n\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, showErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\nconst { inputType, max, min, precision, step } = toRefs(props);\n\nconst isNumber = computed(() => inputType.value === 'number');\nconst numberInputBindings = computed(() =>\n !isNumber.value ? {} : { min: unref(min), max: unref(max), precision: unref(precision), step: unref(step) },\n);\n</script>\n","import { Editor, Extension, Mark, mergeAttributes } from '@tiptap/core';\n\n/**\n * Adds a `class` attribute to paragraph, heading, blockquote and code-block nodes, so the \"Style\" dropdown's\n * named looks (`h3.category`, `p.info-box`, `pre.fancy-code-dark`...) persist through `getHTML()`/`setContent()`\n * the same way any other node attribute does.\n */\nexport const ClassAttribute = Extension.create({\n name: 'classAttribute',\n addGlobalAttributes() {\n return [\n {\n types: ['paragraph', 'heading', 'blockquote', 'codeBlock'],\n attributes: {\n class: {\n default: null,\n parseHTML: (element: HTMLElement) => element.getAttribute('class'),\n renderHTML: (attributes: Record<string, any>) => (attributes.class ? { class: attributes.class } : {}),\n },\n },\n },\n ];\n },\n});\n\nfunction styledSpanMark(name: string, className: string) {\n return Mark.create({\n name,\n parseHTML() {\n return [{ tag: `span.${className}` }];\n },\n renderHTML({ HTMLAttributes }) {\n return ['span', mergeAttributes(HTMLAttributes, { class: className }), 0];\n },\n });\n}\n\n/** Toggle mark wrapping the selection in `<span class=\"marker\">`, behaving like bold/italic over a selection. */\nexport const Marker = styledSpanMark('marker', 'marker');\n/** Toggle mark wrapping the selection in `<span class=\"spoiler\">`, behaving like bold/italic over a selection. */\nexport const Spoiler = styledSpanMark('spoiler', 'spoiler');\n\ninterface BlockStyleDef {\n key: 'ArticleCategory' | 'Title' | 'Subtitle' | 'InfoBox' | 'SideQuote' | 'CodeDark' | 'CodeBright';\n kind: 'heading' | 'paragraph' | 'blockquote' | 'codeBlock';\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n className: string;\n}\n\ninterface MarkStyleDef {\n key: 'Marker' | 'Spoiler';\n kind: 'mark';\n markName: 'marker' | 'spoiler';\n}\n\nexport type StyleDef = BlockStyleDef | MarkStyleDef;\n\n/** The \"Style\" dropdown's entries, in the order they are listed - element/class pairs the toolbar applies. */\nexport const STYLE_DEFS: StyleDef[] = [\n { key: 'ArticleCategory', kind: 'heading', level: 3, className: 'category' },\n { key: 'Title', kind: 'heading', level: 2, className: 'document-title' },\n { key: 'Subtitle', kind: 'heading', level: 3, className: 'document-subtitle' },\n { key: 'InfoBox', kind: 'paragraph', className: 'info-box' },\n { key: 'SideQuote', kind: 'blockquote', className: 'side-quote' },\n { key: 'Marker', kind: 'mark', markName: 'marker' },\n { key: 'Spoiler', kind: 'mark', markName: 'spoiler' },\n { key: 'CodeDark', kind: 'codeBlock', className: 'fancy-code fancy-code-dark' },\n { key: 'CodeBright', kind: 'codeBlock', className: 'fancy-code fancy-code-bright' },\n];\n\n// `editor.isActive(type, attrs)` requires every node touched by the current selection to match, so a\n// selection that spans a styled block plus the empty trailing paragraph TipTap keeps after it (or, after\n// `selectAll` on a single-block document, the whole document) reports no match even though the block the\n// selection starts in carries the style. Reading off the selection's anchor node instead answers the question\n// the dropdown actually asks: \"does the block/mark the selection starts in carry this style\".\n//\n// `$from` for a whole-document `AllSelection` resolves at depth 0 (the boundary before the first child, not\n// inside it), so a depth-0 anchor is re-resolved one position in - a position guaranteed to sit inside the\n// document's first block.\nfunction anchorPos(editor: Editor) {\n const { state } = editor;\n const { $from } = state.selection;\n if ($from.depth > 0 || state.doc.content.size === 0) return $from;\n return state.doc.resolve(Math.min(1, state.doc.content.size));\n}\n\nfunction anchorNode(editor: Editor) {\n return anchorPos(editor).parent;\n}\n\nfunction anchorAncestor(editor: Editor, typeName: string) {\n const $pos = anchorPos(editor);\n for (let depth = $pos.depth; depth >= 0; depth -= 1) {\n if ($pos.node(depth).type.name === typeName) return $pos.node(depth);\n }\n return null;\n}\n\nexport function isStyleActive(editor: Editor, def: StyleDef): boolean {\n switch (def.kind) {\n case 'heading': {\n const node = anchorNode(editor);\n return node.type.name === 'heading' && node.attrs.level === def.level && node.attrs.class === def.className;\n }\n case 'paragraph': {\n const node = anchorNode(editor);\n return node.type.name === 'paragraph' && node.attrs.class === def.className;\n }\n case 'codeBlock': {\n const node = anchorNode(editor);\n return node.type.name === 'codeBlock' && node.attrs.class === def.className;\n }\n case 'blockquote': {\n const node = anchorAncestor(editor, 'blockquote');\n return !!node && node.attrs.class === def.className;\n }\n case 'mark':\n return editor.isActive(def.markName);\n default:\n return false;\n }\n}\n\n/**\n * Applies (or, over an already-styled block/selection, removes) one \"Style\" dropdown entry. Block styles both\n * set the node type and its class in one step; the two inline marks toggle over the current selection like bold\n * or italic.\n */\nexport function applyStyle(editor: Editor, def: StyleDef): void {\n const chain = editor.chain().focus();\n\n // `lift` (which `unsetBlockquote` calls) only acts when every node the selection touches matches the target\n // type - a whole-document `AllSelection` (as `selectAll` produces) also touches the trailing empty paragraph\n // TipTap keeps after the last block, so it never matches and the command silently no-ops. Collapsing such a\n // selection down to the anchor block first keeps every block command below scoped to the block the dropdown\n // means. The two marks are left alone - they need the real selection range to wrap the marked text in.\n const { $from } = editor.state.selection;\n if (def.kind !== 'mark' && $from.depth === 0 && editor.state.doc.content.size > 0) {\n chain.setTextSelection(anchorPos(editor).pos);\n }\n\n switch (def.kind) {\n case 'heading':\n if (isStyleActive(editor, def)) chain.setParagraph().updateAttributes('paragraph', { class: null }).run();\n else {\n chain.setNode('heading', { level: def.level }).updateAttributes('heading', { class: def.className }).run();\n }\n break;\n case 'paragraph':\n if (isStyleActive(editor, def)) chain.setParagraph().updateAttributes('paragraph', { class: null }).run();\n else chain.setParagraph().updateAttributes('paragraph', { class: def.className }).run();\n break;\n case 'blockquote':\n if (isStyleActive(editor, def)) chain.unsetBlockquote().run();\n else if (anchorAncestor(editor, 'blockquote')) {\n chain.updateAttributes('blockquote', { class: def.className }).run();\n } else chain.setBlockquote().updateAttributes('blockquote', { class: def.className }).run();\n break;\n case 'codeBlock':\n if (isStyleActive(editor, def)) chain.toggleCodeBlock().updateAttributes('paragraph', { class: null }).run();\n else if (anchorNode(editor).type.name === 'codeBlock') {\n chain.updateAttributes('codeBlock', { class: def.className }).run();\n } else chain.setCodeBlock().updateAttributes('codeBlock', { class: def.className }).run();\n break;\n case 'mark':\n chain.toggleMark(def.markName).run();\n break;\n default:\n break;\n }\n}\n","import { Fragment, Node as PMNode, Slice } from '@tiptap/pm/model';\nimport { EditorView } from '@tiptap/pm/view';\nimport { Editor } from '@tiptap/vue-3';\n\n/** Reads a `File` into a base64 `data:` URI - the same embedding an uploaded or dropped image goes through. */\nexport function fileToDataUrl(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n}\n\n/**\n * The image files carried alongside (or instead of) HTML on a clipboard paste. Copying a picture out of another\n * app, or a Word/Docs selection that contains embedded pictures, delivers the pixel data this way rather than as\n * an inline `data:` URI in the HTML - `items` covers Chromium and Firefox, `files` is the fallback where a\n * browser only populates that.\n */\nexport function extractImageFiles(dataTransfer: DataTransfer | null): File[] {\n if (!dataTransfer) return [];\n const files: File[] = [];\n Array.from(dataTransfer.items || []).forEach((item) => {\n if (item.kind === 'file') {\n const file = item.getAsFile();\n if (file && file.type.startsWith('image/')) files.push(file);\n }\n });\n if (files.length === 0) {\n Array.from(dataTransfer.files || []).forEach((file) => {\n if (file.type.startsWith('image/')) files.push(file);\n });\n }\n return files;\n}\n\nfunction countImageNodes(fragment: Fragment): number {\n let count = 0;\n fragment.forEach((node) => {\n if (node.type.name === 'image') count += 1;\n else if (node.content.size) count += countImageNodes(node.content);\n });\n return count;\n}\n\nfunction replaceImageSources(fragment: Fragment, urls: string[], cursor: { index: number }): Fragment {\n const children: PMNode[] = [];\n fragment.forEach((node) => {\n if (node.type.name === 'image' && cursor.index < urls.length) {\n children.push(node.type.create({ ...node.attrs, src: urls[cursor.index] }, node.content, node.marks));\n cursor.index += 1;\n } else if (node.content.size) {\n children.push(node.copy(replaceImageSources(node.content, urls, cursor)));\n } else {\n children.push(node);\n }\n });\n return Fragment.fromArray(children);\n}\n\n/**\n * A `handlePaste` for `editorProps`: when the clipboard carries image files, embeds each as a base64 `data:` URI\n * and either drops it into the `<img>` placeholders the pasted HTML already parsed into (order-matched - the\n * shape a Word/Docs selection with embedded pictures takes once `transformPastedHTML` and the schema have parsed\n * it into `slice`), or, where the paste held no HTML worth keeping, inserts the images as new nodes at the\n * selection. Non-image pastes are left to the editor's default handling by returning `false`.\n */\nexport function createImagePasteHandler(getEditor: () => Editor | undefined) {\n return (view: EditorView, event: ClipboardEvent, slice: Slice): boolean => {\n const files = extractImageFiles(event.clipboardData);\n if (files.length === 0) return false;\n\n event.preventDefault();\n\n Promise.all(files.map(fileToDataUrl)).then((urls) => {\n if (countImageNodes(slice.content) > 0) {\n const content = replaceImageSources(slice.content, urls, { index: 0 });\n const newSlice = new Slice(content, slice.openStart, slice.openEnd);\n view.dispatch(view.state.tr.replaceSelection(newSlice).scrollIntoView());\n return;\n }\n\n getEditor()\n ?.chain()\n .focus()\n .insertContent(urls.map((src) => ({ type: 'image', attrs: { src } })))\n .run();\n });\n\n return true;\n };\n}\n","import Link from '@tiptap/extension-link';\n\n/**\n * `Link`, with a `download` attribute the toolbar's \"Downloadable\" toggle can set - rendered as `download=\"file\"`\n * on the anchor.\n */\nexport const LinkWithDownload = Link.extend({\n name: 'link',\n addAttributes() {\n return {\n ...this.parent?.(),\n download: {\n default: null,\n parseHTML: (element: HTMLElement) => element.getAttribute('download'),\n renderHTML: (attributes: Record<string, any>) => (attributes.download ? { download: attributes.download } : {}),\n },\n };\n },\n});\n","import { mergeAttributes, Node } from '@tiptap/core';\n\n/**\n * Recognises a YouTube or Vimeo watch/share URL and returns the equivalent embeddable player URL, or `null` for\n * anything else - the toolbar falls back to inserting the URL as a plain link when this returns `null`.\n */\nexport function toEmbedSrc(url: string): string | null {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n\n const host = parsed.hostname.replace(/^www\\.|^m\\./, '');\n\n if (host === 'youtube.com') {\n const id = parsed.searchParams.get('v');\n if (id) return `https://www.youtube.com/embed/${id}`;\n const embedMatch = parsed.pathname.match(/^\\/embed\\/([\\w-]+)/);\n if (embedMatch) return `https://www.youtube.com/embed/${embedMatch[1]}`;\n const shortsMatch = parsed.pathname.match(/^\\/shorts\\/([\\w-]+)/);\n if (shortsMatch) return `https://www.youtube.com/embed/${shortsMatch[1]}`;\n return null;\n }\n\n if (host === 'youtu.be') {\n const id = parsed.pathname.slice(1);\n return id ? `https://www.youtube.com/embed/${id}` : null;\n }\n\n if (host === 'vimeo.com') {\n const id = parsed.pathname.split('/').filter(Boolean).pop();\n return id && /^\\d+$/.test(id) ? `https://player.vimeo.com/video/${id}` : null;\n }\n\n return null;\n}\n\n/**\n * A responsive `<iframe>` block for a recognised video URL (YouTube, Vimeo) - saved in `getHTML()` output as a\n * plain `iframe.media-embed`, with the responsive 16:9 sizing coming from the editor's own CSS rather than\n * inline styles, so the saved HTML stays provider-agnostic.\n */\nexport const MediaEmbed = Node.create({\n name: 'mediaEmbed',\n group: 'block',\n atom: true,\n draggable: true,\n addAttributes() {\n return {\n src: { default: null },\n };\n },\n parseHTML() {\n return [{ tag: 'iframe.media-embed' }];\n },\n renderHTML({ HTMLAttributes }) {\n return [\n 'iframe',\n mergeAttributes(\n {\n class: 'media-embed',\n frameborder: '0',\n allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture',\n allowfullscreen: 'true',\n },\n HTMLAttributes,\n ),\n ];\n },\n});\n","import { Editor } from '@tiptap/vue-3';\nimport { onBeforeUnmount, Ref, ref, watch } from 'vue';\n\n/**\n * A counter bumped on every editor transaction, and on every `update` (which `setEditable()` emits on its own,\n * without a transaction, to report an editable-state change). The `Editor` instance is not a reactive object, so\n * nothing else tells Vue that `editor.isActive(...)`/`editor.can()...`/`editor.isEditable` now answer differently -\n * a computed that reads this counter before calling them re-evaluates exactly when the editor's state actually\n * changed.\n */\nexport function useEditorTick(editorRef: Ref<Editor | undefined>) {\n const tick = ref(0);\n let bound: Editor | undefined;\n\n const onTick = () => {\n tick.value += 1;\n };\n const bind = (next: Editor | undefined) => {\n bound?.off('transaction', onTick);\n bound?.off('update', onTick);\n bound = next;\n bound?.on('transaction', onTick);\n bound?.on('update', onTick);\n };\n\n watch(editorRef, bind, { immediate: true });\n onBeforeUnmount(() => bind(undefined));\n\n return tick;\n}\n","<template>\n <div class=\"rtf-toolbar\" :class=\"{ 'rtf-toolbar--disabled': !editable }\">\n <df-actions :actions=\"undoRedoActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n rounded=\"sm\"\n :title=\"t.SelectAll\"\n @click=\"editor?.chain().focus().selectAll().run()\"\n >\n <cached-icon name=\"mdi-select-all\" />\n </v-btn>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" append-icon=\"mdi-chevron-down\">\n {{ headingLabel }}\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item\n v-for=\"option in headingOptions\"\n :key=\"option.level\"\n :active=\"isHeadingActive(option.level)\"\n @click=\"setHeading(option.level)\"\n >\n <v-list-item-title>{{ option.label }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" append-icon=\"mdi-chevron-down\">\n {{ t.Style }}\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item\n v-for=\"def in styleDefs\"\n :key=\"def.key\"\n :active=\"styleActive(def)\"\n @click=\"editor && applyStyle(editor, def)\"\n >\n <v-list-item-title>{{ t[def.key] }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"boldItalicActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <div class=\"rtf-toolbar-group\">\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n :title=\"t.HorizontalLine\"\n @click=\"editor?.chain().focus().setHorizontalRule().run()\"\n >\n <cached-icon name=\"mdi-minus\" />\n </v-btn>\n\n <v-menu :close-on-content-click=\"false\" @update:model-value=\"(shown: boolean) => shown && openLinkMenu()\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t.Link\" :active=\"state.link\">\n <cached-icon name=\"mdi-link-variant\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"linkUrl\"\n :label=\"t.LinkUrl\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"applyLink\"\n />\n <v-checkbox v-model=\"linkDownloadable\" :label=\"t.Downloadable\" density=\"compact\" hide-details class=\"mt-1\" />\n <div class=\"d-flex justify-end ga-2 mt-2\">\n <v-btn v-if=\"state.link\" size=\"small\" variant=\"text\" @click=\"removeLink\">{{ t.LinkRemove }}</v-btn>\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"applyLink\">{{ t.LinkApply }}</v-btn>\n </div>\n </v-card>\n </v-menu>\n\n <v-menu :close-on-content-click=\"false\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t.Image\">\n <cached-icon name=\"mdi-image-plus\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"imageUrl\"\n :label=\"t.ImageUrl\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"insertImageFromUrl\"\n />\n <div class=\"d-flex justify-space-between align-center ga-2 mt-2\">\n <v-btn size=\"small\" variant=\"text\" prepend-icon=\"mdi-upload\" @click=\"triggerImageUpload\">\n {{ t.ImageUpload }}\n </v-btn>\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"insertImageFromUrl\">\n {{ t.ImageInsert }}\n </v-btn>\n </div>\n </v-card>\n </v-menu>\n <input ref=\"imageInput\" type=\"file\" accept=\"image/*\" class=\"d-none\" @change=\"onImageFileChosen\" />\n\n <v-menu :close-on-content-click=\"false\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t.MediaEmbed\">\n <cached-icon name=\"mdi-video-plus\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"embedUrl\"\n :label=\"t.MediaEmbedUrl\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"insertMediaEmbed\"\n />\n <div class=\"d-flex justify-end mt-2\">\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"insertMediaEmbed\">\n {{ t.MediaEmbedInsert }}\n </v-btn>\n </div>\n </v-card>\n </v-menu>\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t.Table\">\n <cached-icon name=\"mdi-table\" />\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item @click=\"editor?.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()\">\n <template #prepend><cached-icon name=\"mdi-table-plus\" /></template>\n <v-list-item-title>{{ t.TableInsert }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addRowBefore().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-plus-before\" /></template>\n <v-list-item-title>{{ t.TableAddRowAbove }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addRowAfter().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-plus-after\" /></template>\n <v-list-item-title>{{ t.TableAddRowBelow }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteRow().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-remove\" /></template>\n <v-list-item-title>{{ t.TableDeleteRow }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addColumnBefore().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-plus-before\" /></template>\n <v-list-item-title>{{ t.TableAddColumnBefore }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addColumnAfter().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-plus-after\" /></template>\n <v-list-item-title>{{ t.TableAddColumnAfter }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteColumn().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-remove\" /></template>\n <v-list-item-title>{{ t.TableDeleteColumn }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().toggleHeaderRow().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row\" /></template>\n <v-list-item-title>{{ t.TableToggleHeaderRow }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteTable().run()\">\n <template #prepend><cached-icon name=\"mdi-table-remove\" /></template>\n <v-list-item-title>{{ t.TableDeleteTable }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n :title=\"t.Blockquote\"\n :active=\"state.blockquote\"\n @click=\"editor?.chain().focus().toggleBlockquote().run()\"\n >\n <cached-icon name=\"mdi-format-quote-close\" />\n </v-btn>\n </div>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"alignActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"listActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Action, ExecuteAction } from '@dynamicforms/vue-forms';\nimport { Editor } from '@tiptap/vue-3';\nimport { isEqual } from 'lodash-es';\nimport { computed, ref, watchEffect } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport DfActions from '../../df-actions.vue';\nimport { ActionDisplayStyle, ActionRenderOptions } from '../action';\nimport { VuetifyButtonSize } from '../input-base';\nimport { translatableStrings } from '../translations';\n\nimport { applyStyle, isStyleActive, STYLE_DEFS } from './block-styles';\nimport { fileToDataUrl } from './image-paste';\nimport { toEmbedSrc } from './media-embed';\nimport { useEditorTick } from './use-editor-tick';\n\nconst props = withDefaults(defineProps<{ editor?: Editor; buttonSize?: VuetifyButtonSize }>(), {\n editor: undefined,\n buttonSize: 'small',\n});\n\nconst buttonSize = computed(() => props.buttonSize);\n\nconst t = translatableStrings;\n\nconst editor = computed(() => props.editor);\nconst tick = useEditorTick(editor);\nconst editable = computed(() => {\n void tick.value;\n return !!props.editor?.isEditable;\n});\n\n// Shared across every standalone `<v-btn>`/`<df-actions>` in this toolbar, so a call site states only what\n// actually varies between buttons (icon, title, active/click handler) rather than repeating this on each one.\nconst toolbarButtonProps = computed(() => ({\n size: buttonSize.value,\n density: 'comfortable' as const,\n variant: 'text' as const,\n disabled: !editable.value,\n}));\nconst dfActionsProps = computed(() => ({ buttonSize: buttonSize.value, buttonDensity: 'comfortable' as const }));\n\nconst state = computed(() => {\n void tick.value;\n const e = props.editor;\n return {\n canUndo: !!e?.can().undo(),\n canRedo: !!e?.can().redo(),\n bold: !!e?.isActive('bold'),\n italic: !!e?.isActive('italic'),\n link: !!e?.isActive('link'),\n blockquote: !!e?.isActive('blockquote'),\n bulletList: !!e?.isActive('bulletList'),\n orderedList: !!e?.isActive('orderedList'),\n alignLeft: !!e?.isActive({ textAlign: 'left' }),\n alignCenter: !!e?.isActive({ textAlign: 'center' }),\n alignRight: !!e?.isActive({ textAlign: 'right' }),\n alignJustify: !!e?.isActive({ textAlign: 'justify' }),\n inTable: !!e?.isActive('table'),\n canLift: !!e?.can().liftListItem('listItem'),\n canSink: !!e?.can().sinkListItem('listItem'),\n };\n});\n\nconst alignValue = computed(() => {\n if (state.value.alignLeft) return 'left';\n if (state.value.alignCenter) return 'center';\n if (state.value.alignRight) return 'right';\n if (state.value.alignJustify) return 'justify';\n return undefined;\n});\n\nfunction setAlign(value: unknown) {\n if (typeof value !== 'string') return;\n editor.value?.chain().focus().setTextAlign(value).run();\n}\n\ninterface ToolbarActionSync {\n action: Action<ActionRenderOptions>;\n title: () => string;\n disabled: () => boolean;\n active?: () => boolean;\n}\n\nconst toolbarActionSyncs: ToolbarActionSync[] = [];\n\n// Static button clusters rendered through `<df-actions>` rather than `<v-btn-group>`/`<v-btn-toggle>`: each\n// button is a self-contained `Action`, so its look (size, rounded corners, active/disabled state) is drawn\n// from its own value rather than from props a parent component may or may not forward to it.\n//\n// `title`/`disabled`/`active` are getters, not one-off values, because an `Action`'s `value`/`enabled` are plain\n// assignments rather than bindings to a computed - the `watchEffect` below re-runs them on every reactive change\n// and writes the result into the action it was registered against.\nfunction toolbarAction(\n icon: string,\n onClick: () => void,\n title: () => string,\n disabled: () => boolean,\n active?: () => boolean,\n): Action<ActionRenderOptions> {\n const action = new Action<ActionRenderOptions>({\n value: { icon, renderAs: ActionDisplayStyle.TEXT, showIcon: true, showLabel: false },\n actions: [\n new ExecuteAction((a, supr, params) => {\n onClick();\n return supr(a, params);\n }),\n ],\n });\n toolbarActionSyncs.push({ action, title, disabled, active });\n return action;\n}\n\nfunction syncToolbarAction({ action, title, disabled, active }: ToolbarActionSync) {\n // `value` writes first: `Action`/`Field` refuses to change `value` while `enabled` is false, so flipping\n // `enabled` first would lock passthroughAttrs (the button's title/active state) to whatever it last held\n // the moment a button first goes disabled.\n const wantAttrs: Record<string, unknown> = { title: title(), icon: true };\n if (active) wantAttrs.active = active();\n if (!isEqual(action.value.passthroughAttrs ?? {}, wantAttrs)) {\n action.value = { ...action.value, passthroughAttrs: wantAttrs };\n }\n\n const wantEnabled = !disabled();\n if (action.enabled !== wantEnabled) action.enabled = wantEnabled;\n}\n\nconst undoRedoActions = [\n toolbarAction(\n 'mdi-undo',\n () => editor.value?.chain().focus().undo().run(),\n () => t.Undo,\n () => !editable.value || !state.value.canUndo,\n ),\n toolbarAction(\n 'mdi-redo',\n () => editor.value?.chain().focus().redo().run(),\n () => t.Redo,\n () => !editable.value || !state.value.canRedo,\n ),\n];\n\nconst boldItalicActions = [\n toolbarAction(\n 'mdi-format-bold',\n () => editor.value?.chain().focus().toggleBold().run(),\n () => t.Bold,\n () => !editable.value,\n () => state.value.bold,\n ),\n toolbarAction(\n 'mdi-format-italic',\n () => editor.value?.chain().focus().toggleItalic().run(),\n () => t.Italic,\n () => !editable.value,\n () => state.value.italic,\n ),\n];\n\nconst ALIGN_DEFS: { value: string; icon: string; title: () => string }[] = [\n { value: 'left', icon: 'mdi-format-align-left', title: () => t.AlignLeft },\n { value: 'center', icon: 'mdi-format-align-center', title: () => t.AlignCenter },\n { value: 'right', icon: 'mdi-format-align-right', title: () => t.AlignRight },\n { value: 'justify', icon: 'mdi-format-align-justify', title: () => t.AlignJustify },\n];\nconst alignActions = ALIGN_DEFS.map((def) =>\n toolbarAction(\n def.icon,\n () => setAlign(def.value),\n def.title,\n () => !editable.value,\n () => alignValue.value === def.value,\n ),\n);\n\nconst listActions = [\n toolbarAction(\n 'mdi-format-list-bulleted',\n () => editor.value?.chain().focus().toggleBulletList().run(),\n () => t.BulletedList,\n () => !editable.value,\n () => state.value.bulletList,\n ),\n toolbarAction(\n 'mdi-format-list-numbered',\n () => editor.value?.chain().focus().toggleOrderedList().run(),\n () => t.NumberedList,\n () => !editable.value,\n () => state.value.orderedList,\n ),\n toolbarAction(\n 'mdi-format-indent-decrease',\n () => editor.value?.chain().focus().liftListItem('listItem').run(),\n () => t.Outdent,\n () => !editable.value || !state.value.canLift,\n ),\n toolbarAction(\n 'mdi-format-indent-increase',\n () => editor.value?.chain().focus().sinkListItem('listItem').run(),\n () => t.Indent,\n () => !editable.value || !state.value.canSink,\n ),\n];\n\nwatchEffect(() => {\n toolbarActionSyncs.forEach(syncToolbarAction);\n});\n\nconst headingOptions = computed(\n () =>\n [\n { level: 0, label: t.Paragraph },\n { level: 1, label: t.Heading1 },\n { level: 2, label: t.Heading2 },\n { level: 3, label: t.Heading3 },\n { level: 4, label: t.Heading4 },\n { level: 5, label: t.Heading5 },\n { level: 6, label: t.Heading6 },\n ] as const,\n);\n\nfunction isHeadingActive(level: number) {\n void tick.value;\n if (level === 0) return !!editor.value?.isActive('paragraph');\n return !!editor.value?.isActive('heading', { level });\n}\nconst headingLabel = computed(\n () => headingOptions.value.find((option) => isHeadingActive(option.level))?.label ?? t.Paragraph,\n);\n\nfunction setHeading(level: number) {\n const chain = editor.value?.chain().focus();\n if (!chain) return;\n if (level === 0) chain.setParagraph().run();\n else chain.toggleHeading({ level: level as 1 | 2 | 3 | 4 | 5 | 6 }).run();\n}\n\n// Style dropdown\nconst styleDefs = STYLE_DEFS;\nfunction styleActive(def: (typeof STYLE_DEFS)[number]) {\n void tick.value;\n return !!editor.value && isStyleActive(editor.value, def);\n}\n\n// Link menu\nconst linkUrl = ref('');\nconst linkDownloadable = ref(false);\nfunction openLinkMenu() {\n const attrs = editor.value?.getAttributes('link') ?? {};\n linkUrl.value = attrs.href ?? '';\n linkDownloadable.value = !!attrs.download;\n}\nfunction applyLink() {\n if (!linkUrl.value) return;\n editor.value\n ?.chain()\n .focus()\n .extendMarkRange('link')\n .setLink({ href: linkUrl.value })\n .updateAttributes('link', { download: linkDownloadable.value ? 'file' : null })\n .run();\n}\nfunction removeLink() {\n editor.value?.chain().focus().unsetLink().run();\n}\n\n// Image menu\nconst imageUrl = ref('');\nconst imageInput = ref<HTMLInputElement>();\nfunction insertImageFromUrl() {\n if (!imageUrl.value) return;\n editor.value?.chain().focus().setImage({ src: imageUrl.value }).run();\n imageUrl.value = '';\n}\nfunction triggerImageUpload() {\n imageInput.value?.click();\n}\nasync function onImageFileChosen(event: Event) {\n const file = (event.target as HTMLInputElement).files?.[0];\n if (!file) return;\n const src = await fileToDataUrl(file);\n editor.value?.chain().focus().setImage({ src }).run();\n (event.target as HTMLInputElement).value = '';\n}\n\n// Media embed menu\nconst embedUrl = ref('');\nfunction insertMediaEmbed() {\n if (!embedUrl.value) return;\n const src = toEmbedSrc(embedUrl.value);\n const chain = editor.value?.chain().focus();\n if (!chain) return;\n if (src) chain.insertContent({ type: 'mediaEmbed', attrs: { src } }).run();\n else {\n chain\n .insertContent({ type: 'text', text: embedUrl.value, marks: [{ type: 'link', attrs: { href: embedUrl.value } }] })\n .run();\n }\n embedUrl.value = '';\n}\n</script>\n\n<style>\n.rtf-toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 2px;\n padding: 4px;\n overflow-x: auto;\n border-bottom: 1px solid rgb(var(--v-theme-surface-variant));\n}\n\n.rtf-toolbar--disabled {\n opacity: 0.6;\n}\n\n/* Mirrors `<df-actions>`'s own `button-group` look for the one cluster it can't render (it has no slot for a\n `v-menu` activator): a plain flex row rather than Vuetify's `v-btn-group`, whose child buttons are sized by a\n different formula than a standalone (or `<df-actions>`-rendered) icon button of the same `size`. */\n.rtf-toolbar-group {\n display: flex;\n}\n\n.rtf-toolbar-group .v-btn {\n border-radius: 0;\n}\n\n.rtf-toolbar-group .v-btn:first-child {\n border-start-start-radius: 0.5em;\n border-end-start-radius: 0.5em;\n}\n\n.rtf-toolbar-group .v-btn:last-child {\n border-start-end-radius: 0.5em;\n border-end-end-radius: 0.5em;\n}\n</style>\n","<template>\n <div class=\"rtf-toolbar\" :class=\"{ 'rtf-toolbar--disabled': !editable }\">\n <df-actions :actions=\"undoRedoActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n rounded=\"sm\"\n :title=\"t.SelectAll\"\n @click=\"editor?.chain().focus().selectAll().run()\"\n >\n <cached-icon name=\"mdi-select-all\" />\n </v-btn>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" append-icon=\"mdi-chevron-down\">\n {{ headingLabel }}\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item\n v-for=\"option in headingOptions\"\n :key=\"option.level\"\n :active=\"isHeadingActive(option.level)\"\n @click=\"setHeading(option.level)\"\n >\n <v-list-item-title>{{ option.label }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" append-icon=\"mdi-chevron-down\">\n {{ t.Style }}\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item\n v-for=\"def in styleDefs\"\n :key=\"def.key\"\n :active=\"styleActive(def)\"\n @click=\"editor && applyStyle(editor, def)\"\n >\n <v-list-item-title>{{ t[def.key] }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"boldItalicActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <div class=\"rtf-toolbar-group\">\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n :title=\"t.HorizontalLine\"\n @click=\"editor?.chain().focus().setHorizontalRule().run()\"\n >\n <cached-icon name=\"mdi-minus\" />\n </v-btn>\n\n <v-menu :close-on-content-click=\"false\" @update:model-value=\"(shown: boolean) => shown && openLinkMenu()\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t.Link\" :active=\"state.link\">\n <cached-icon name=\"mdi-link-variant\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"linkUrl\"\n :label=\"t.LinkUrl\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"applyLink\"\n />\n <v-checkbox v-model=\"linkDownloadable\" :label=\"t.Downloadable\" density=\"compact\" hide-details class=\"mt-1\" />\n <div class=\"d-flex justify-end ga-2 mt-2\">\n <v-btn v-if=\"state.link\" size=\"small\" variant=\"text\" @click=\"removeLink\">{{ t.LinkRemove }}</v-btn>\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"applyLink\">{{ t.LinkApply }}</v-btn>\n </div>\n </v-card>\n </v-menu>\n\n <v-menu :close-on-content-click=\"false\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t.Image\">\n <cached-icon name=\"mdi-image-plus\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"imageUrl\"\n :label=\"t.ImageUrl\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"insertImageFromUrl\"\n />\n <div class=\"d-flex justify-space-between align-center ga-2 mt-2\">\n <v-btn size=\"small\" variant=\"text\" prepend-icon=\"mdi-upload\" @click=\"triggerImageUpload\">\n {{ t.ImageUpload }}\n </v-btn>\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"insertImageFromUrl\">\n {{ t.ImageInsert }}\n </v-btn>\n </div>\n </v-card>\n </v-menu>\n <input ref=\"imageInput\" type=\"file\" accept=\"image/*\" class=\"d-none\" @change=\"onImageFileChosen\" />\n\n <v-menu :close-on-content-click=\"false\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t.MediaEmbed\">\n <cached-icon name=\"mdi-video-plus\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"embedUrl\"\n :label=\"t.MediaEmbedUrl\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"insertMediaEmbed\"\n />\n <div class=\"d-flex justify-end mt-2\">\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"insertMediaEmbed\">\n {{ t.MediaEmbedInsert }}\n </v-btn>\n </div>\n </v-card>\n </v-menu>\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t.Table\">\n <cached-icon name=\"mdi-table\" />\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item @click=\"editor?.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()\">\n <template #prepend><cached-icon name=\"mdi-table-plus\" /></template>\n <v-list-item-title>{{ t.TableInsert }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addRowBefore().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-plus-before\" /></template>\n <v-list-item-title>{{ t.TableAddRowAbove }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addRowAfter().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-plus-after\" /></template>\n <v-list-item-title>{{ t.TableAddRowBelow }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteRow().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-remove\" /></template>\n <v-list-item-title>{{ t.TableDeleteRow }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addColumnBefore().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-plus-before\" /></template>\n <v-list-item-title>{{ t.TableAddColumnBefore }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addColumnAfter().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-plus-after\" /></template>\n <v-list-item-title>{{ t.TableAddColumnAfter }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteColumn().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-remove\" /></template>\n <v-list-item-title>{{ t.TableDeleteColumn }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().toggleHeaderRow().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row\" /></template>\n <v-list-item-title>{{ t.TableToggleHeaderRow }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteTable().run()\">\n <template #prepend><cached-icon name=\"mdi-table-remove\" /></template>\n <v-list-item-title>{{ t.TableDeleteTable }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n :title=\"t.Blockquote\"\n :active=\"state.blockquote\"\n @click=\"editor?.chain().focus().toggleBlockquote().run()\"\n >\n <cached-icon name=\"mdi-format-quote-close\" />\n </v-btn>\n </div>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"alignActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"listActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Action, ExecuteAction } from '@dynamicforms/vue-forms';\nimport { Editor } from '@tiptap/vue-3';\nimport { isEqual } from 'lodash-es';\nimport { computed, ref, watchEffect } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport DfActions from '../../df-actions.vue';\nimport { ActionDisplayStyle, ActionRenderOptions } from '../action';\nimport { VuetifyButtonSize } from '../input-base';\nimport { translatableStrings } from '../translations';\n\nimport { applyStyle, isStyleActive, STYLE_DEFS } from './block-styles';\nimport { fileToDataUrl } from './image-paste';\nimport { toEmbedSrc } from './media-embed';\nimport { useEditorTick } from './use-editor-tick';\n\nconst props = withDefaults(defineProps<{ editor?: Editor; buttonSize?: VuetifyButtonSize }>(), {\n editor: undefined,\n buttonSize: 'small',\n});\n\nconst buttonSize = computed(() => props.buttonSize);\n\nconst t = translatableStrings;\n\nconst editor = computed(() => props.editor);\nconst tick = useEditorTick(editor);\nconst editable = computed(() => {\n void tick.value;\n return !!props.editor?.isEditable;\n});\n\n// Shared across every standalone `<v-btn>`/`<df-actions>` in this toolbar, so a call site states only what\n// actually varies between buttons (icon, title, active/click handler) rather than repeating this on each one.\nconst toolbarButtonProps = computed(() => ({\n size: buttonSize.value,\n density: 'comfortable' as const,\n variant: 'text' as const,\n disabled: !editable.value,\n}));\nconst dfActionsProps = computed(() => ({ buttonSize: buttonSize.value, buttonDensity: 'comfortable' as const }));\n\nconst state = computed(() => {\n void tick.value;\n const e = props.editor;\n return {\n canUndo: !!e?.can().undo(),\n canRedo: !!e?.can().redo(),\n bold: !!e?.isActive('bold'),\n italic: !!e?.isActive('italic'),\n link: !!e?.isActive('link'),\n blockquote: !!e?.isActive('blockquote'),\n bulletList: !!e?.isActive('bulletList'),\n orderedList: !!e?.isActive('orderedList'),\n alignLeft: !!e?.isActive({ textAlign: 'left' }),\n alignCenter: !!e?.isActive({ textAlign: 'center' }),\n alignRight: !!e?.isActive({ textAlign: 'right' }),\n alignJustify: !!e?.isActive({ textAlign: 'justify' }),\n inTable: !!e?.isActive('table'),\n canLift: !!e?.can().liftListItem('listItem'),\n canSink: !!e?.can().sinkListItem('listItem'),\n };\n});\n\nconst alignValue = computed(() => {\n if (state.value.alignLeft) return 'left';\n if (state.value.alignCenter) return 'center';\n if (state.value.alignRight) return 'right';\n if (state.value.alignJustify) return 'justify';\n return undefined;\n});\n\nfunction setAlign(value: unknown) {\n if (typeof value !== 'string') return;\n editor.value?.chain().focus().setTextAlign(value).run();\n}\n\ninterface ToolbarActionSync {\n action: Action<ActionRenderOptions>;\n title: () => string;\n disabled: () => boolean;\n active?: () => boolean;\n}\n\nconst toolbarActionSyncs: ToolbarActionSync[] = [];\n\n// Static button clusters rendered through `<df-actions>` rather than `<v-btn-group>`/`<v-btn-toggle>`: each\n// button is a self-contained `Action`, so its look (size, rounded corners, active/disabled state) is drawn\n// from its own value rather than from props a parent component may or may not forward to it.\n//\n// `title`/`disabled`/`active` are getters, not one-off values, because an `Action`'s `value`/`enabled` are plain\n// assignments rather than bindings to a computed - the `watchEffect` below re-runs them on every reactive change\n// and writes the result into the action it was registered against.\nfunction toolbarAction(\n icon: string,\n onClick: () => void,\n title: () => string,\n disabled: () => boolean,\n active?: () => boolean,\n): Action<ActionRenderOptions> {\n const action = new Action<ActionRenderOptions>({\n value: { icon, renderAs: ActionDisplayStyle.TEXT, showIcon: true, showLabel: false },\n actions: [\n new ExecuteAction((a, supr, params) => {\n onClick();\n return supr(a, params);\n }),\n ],\n });\n toolbarActionSyncs.push({ action, title, disabled, active });\n return action;\n}\n\nfunction syncToolbarAction({ action, title, disabled, active }: ToolbarActionSync) {\n // `value` writes first: `Action`/`Field` refuses to change `value` while `enabled` is false, so flipping\n // `enabled` first would lock passthroughAttrs (the button's title/active state) to whatever it last held\n // the moment a button first goes disabled.\n const wantAttrs: Record<string, unknown> = { title: title(), icon: true };\n if (active) wantAttrs.active = active();\n if (!isEqual(action.value.passthroughAttrs ?? {}, wantAttrs)) {\n action.value = { ...action.value, passthroughAttrs: wantAttrs };\n }\n\n const wantEnabled = !disabled();\n if (action.enabled !== wantEnabled) action.enabled = wantEnabled;\n}\n\nconst undoRedoActions = [\n toolbarAction(\n 'mdi-undo',\n () => editor.value?.chain().focus().undo().run(),\n () => t.Undo,\n () => !editable.value || !state.value.canUndo,\n ),\n toolbarAction(\n 'mdi-redo',\n () => editor.value?.chain().focus().redo().run(),\n () => t.Redo,\n () => !editable.value || !state.value.canRedo,\n ),\n];\n\nconst boldItalicActions = [\n toolbarAction(\n 'mdi-format-bold',\n () => editor.value?.chain().focus().toggleBold().run(),\n () => t.Bold,\n () => !editable.value,\n () => state.value.bold,\n ),\n toolbarAction(\n 'mdi-format-italic',\n () => editor.value?.chain().focus().toggleItalic().run(),\n () => t.Italic,\n () => !editable.value,\n () => state.value.italic,\n ),\n];\n\nconst ALIGN_DEFS: { value: string; icon: string; title: () => string }[] = [\n { value: 'left', icon: 'mdi-format-align-left', title: () => t.AlignLeft },\n { value: 'center', icon: 'mdi-format-align-center', title: () => t.AlignCenter },\n { value: 'right', icon: 'mdi-format-align-right', title: () => t.AlignRight },\n { value: 'justify', icon: 'mdi-format-align-justify', title: () => t.AlignJustify },\n];\nconst alignActions = ALIGN_DEFS.map((def) =>\n toolbarAction(\n def.icon,\n () => setAlign(def.value),\n def.title,\n () => !editable.value,\n () => alignValue.value === def.value,\n ),\n);\n\nconst listActions = [\n toolbarAction(\n 'mdi-format-list-bulleted',\n () => editor.value?.chain().focus().toggleBulletList().run(),\n () => t.BulletedList,\n () => !editable.value,\n () => state.value.bulletList,\n ),\n toolbarAction(\n 'mdi-format-list-numbered',\n () => editor.value?.chain().focus().toggleOrderedList().run(),\n () => t.NumberedList,\n () => !editable.value,\n () => state.value.orderedList,\n ),\n toolbarAction(\n 'mdi-format-indent-decrease',\n () => editor.value?.chain().focus().liftListItem('listItem').run(),\n () => t.Outdent,\n () => !editable.value || !state.value.canLift,\n ),\n toolbarAction(\n 'mdi-format-indent-increase',\n () => editor.value?.chain().focus().sinkListItem('listItem').run(),\n () => t.Indent,\n () => !editable.value || !state.value.canSink,\n ),\n];\n\nwatchEffect(() => {\n toolbarActionSyncs.forEach(syncToolbarAction);\n});\n\nconst headingOptions = computed(\n () =>\n [\n { level: 0, label: t.Paragraph },\n { level: 1, label: t.Heading1 },\n { level: 2, label: t.Heading2 },\n { level: 3, label: t.Heading3 },\n { level: 4, label: t.Heading4 },\n { level: 5, label: t.Heading5 },\n { level: 6, label: t.Heading6 },\n ] as const,\n);\n\nfunction isHeadingActive(level: number) {\n void tick.value;\n if (level === 0) return !!editor.value?.isActive('paragraph');\n return !!editor.value?.isActive('heading', { level });\n}\nconst headingLabel = computed(\n () => headingOptions.value.find((option) => isHeadingActive(option.level))?.label ?? t.Paragraph,\n);\n\nfunction setHeading(level: number) {\n const chain = editor.value?.chain().focus();\n if (!chain) return;\n if (level === 0) chain.setParagraph().run();\n else chain.toggleHeading({ level: level as 1 | 2 | 3 | 4 | 5 | 6 }).run();\n}\n\n// Style dropdown\nconst styleDefs = STYLE_DEFS;\nfunction styleActive(def: (typeof STYLE_DEFS)[number]) {\n void tick.value;\n return !!editor.value && isStyleActive(editor.value, def);\n}\n\n// Link menu\nconst linkUrl = ref('');\nconst linkDownloadable = ref(false);\nfunction openLinkMenu() {\n const attrs = editor.value?.getAttributes('link') ?? {};\n linkUrl.value = attrs.href ?? '';\n linkDownloadable.value = !!attrs.download;\n}\nfunction applyLink() {\n if (!linkUrl.value) return;\n editor.value\n ?.chain()\n .focus()\n .extendMarkRange('link')\n .setLink({ href: linkUrl.value })\n .updateAttributes('link', { download: linkDownloadable.value ? 'file' : null })\n .run();\n}\nfunction removeLink() {\n editor.value?.chain().focus().unsetLink().run();\n}\n\n// Image menu\nconst imageUrl = ref('');\nconst imageInput = ref<HTMLInputElement>();\nfunction insertImageFromUrl() {\n if (!imageUrl.value) return;\n editor.value?.chain().focus().setImage({ src: imageUrl.value }).run();\n imageUrl.value = '';\n}\nfunction triggerImageUpload() {\n imageInput.value?.click();\n}\nasync function onImageFileChosen(event: Event) {\n const file = (event.target as HTMLInputElement).files?.[0];\n if (!file) return;\n const src = await fileToDataUrl(file);\n editor.value?.chain().focus().setImage({ src }).run();\n (event.target as HTMLInputElement).value = '';\n}\n\n// Media embed menu\nconst embedUrl = ref('');\nfunction insertMediaEmbed() {\n if (!embedUrl.value) return;\n const src = toEmbedSrc(embedUrl.value);\n const chain = editor.value?.chain().focus();\n if (!chain) return;\n if (src) chain.insertContent({ type: 'mediaEmbed', attrs: { src } }).run();\n else {\n chain\n .insertContent({ type: 'text', text: embedUrl.value, marks: [{ type: 'link', attrs: { href: embedUrl.value } }] })\n .run();\n }\n embedUrl.value = '';\n}\n</script>\n\n<style>\n.rtf-toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 2px;\n padding: 4px;\n overflow-x: auto;\n border-bottom: 1px solid rgb(var(--v-theme-surface-variant));\n}\n\n.rtf-toolbar--disabled {\n opacity: 0.6;\n}\n\n/* Mirrors `<df-actions>`'s own `button-group` look for the one cluster it can't render (it has no slot for a\n `v-menu` activator): a plain flex row rather than Vuetify's `v-btn-group`, whose child buttons are sized by a\n different formula than a standalone (or `<df-actions>`-rendered) icon button of the same `size`. */\n.rtf-toolbar-group {\n display: flex;\n}\n\n.rtf-toolbar-group .v-btn {\n border-radius: 0;\n}\n\n.rtf-toolbar-group .v-btn:first-child {\n border-start-start-radius: 0.5em;\n border-end-start-radius: 0.5em;\n}\n\n.rtf-toolbar-group .v-btn:last-child {\n border-start-end-radius: 0.5em;\n border-end-end-radius: 0.5em;\n}\n</style>\n","// Content copied from Word or Google Docs carries mso-* inline styles, Mso*-prefixed classes, namespaced tags\n// (o:p, w:sdt, v:shape...), and conditional-compilation comments that are meaningless outside their originating\n// document. Left in place, they either render as visible clutter or silently defeat the mark/heading detection\n// the editor's own paste parsing relies on (an inline `mso-bidi-font-weight` next to a real `font-weight:bold`\n// is harmless, but a class name colliding with one this library uses for content styling would not be).\nconst NAMESPACED_TAG = /^[a-z][a-z0-9]*:[a-z]/i;\nconst MSO_STYLE_PROPERTY = /mso-[a-z-]+\\s*:[^;]+;?/gi;\nconst MSO_CLASS = /^Mso/i;\n// Word's own cell/table shading (Automatic/theme colours resolved at copy time, not necessarily what the\n// document visibly showed) rides along as a plain, non-mso `background`/`background-color` - stripped so a\n// pasted table adopts the editor's own theme instead of carrying the source document's shading. Foreground\n// `color` is left alone: unlike background shading, it is usually deliberate content styling worth keeping.\nconst BACKGROUND_STYLE_PROPERTY = /background(?:-color)?\\s*:[^;]+;?/gi;\n\nfunction stripComments(root: Element) {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n const comments: Comment[] = [];\n for (let node = walker.nextNode(); node; node = walker.nextNode()) comments.push(node as Comment);\n comments.forEach((comment) => comment.parentNode?.removeChild(comment));\n}\n\nfunction unwrap(element: Element) {\n const parent = element.parentNode;\n if (!parent) return;\n while (element.firstChild) parent.insertBefore(element.firstChild, element);\n parent.removeChild(element);\n}\n\nfunction cleanAttributes(element: HTMLElement) {\n const style = element.getAttribute('style');\n if (style != null) {\n const cleaned = style.replace(MSO_STYLE_PROPERTY, '').replace(BACKGROUND_STYLE_PROPERTY, '').trim();\n if (cleaned) element.setAttribute('style', cleaned);\n else element.removeAttribute('style');\n }\n\n const cssClass = element.getAttribute('class');\n if (cssClass != null) {\n const cleaned = cssClass\n .split(/\\s+/)\n .filter((name) => name && !MSO_CLASS.test(name))\n .join(' ');\n if (cleaned) element.setAttribute('class', cleaned);\n else element.removeAttribute('class');\n }\n\n element.removeAttribute('lang');\n element.removeAttribute('xml:lang');\n element.removeAttribute('id');\n element.removeAttribute('align');\n element.removeAttribute('bgcolor');\n}\n\n/**\n * Strips Word/Google Docs clipboard artifacts from pasted HTML before it reaches the editor's schema parser:\n * conditional comments, `<xml>`/`<style>`/`<meta>` blocks, namespaced tags (`o:p`, `w:sdt`, `v:shape`...),\n * `mso-*` inline style properties, `Mso*` classes, `background`/`background-color`/`bgcolor` shading, and\n * `lang`/`id`/`align` attributes. Real formatting left behind (`font-weight`, `<b>`, `<table>`, `<h1>`...) is\n * untouched, since it is what the editor's own extensions parse into marks, headings, lists and tables.\n */\nexport function stripWordArtifacts(html: string): string {\n if (!html || typeof DOMParser === 'undefined') return html;\n\n const doc = new DOMParser().parseFromString(html, 'text/html');\n const root = doc.body;\n if (!root) return html;\n\n stripComments(root);\n root.querySelectorAll('xml, style, script, meta, link').forEach((node) => node.remove());\n\n Array.from(root.querySelectorAll<HTMLElement>('*')).forEach((element) => {\n if (NAMESPACED_TAG.test(element.tagName) || element.tagName === 'FONT') {\n unwrap(element);\n return;\n }\n cleanAttributes(element);\n });\n\n // A span or div left with no attributes after cleanup is a pure wrapper Word adds around every run of text.\n Array.from(root.querySelectorAll('span, div')).forEach((element) => {\n if (element.attributes.length === 0) unwrap(element);\n });\n\n return root.innerHTML;\n}\n","<template>\n <div class=\"editor-container\">\n <rtf-toolbar ref=\"toolbarRef\" :editor=\"editor\" :button-size=\"toolbarButtonSize\" />\n <editor-content class=\"editor-container__editor\" :editor=\"editor\" />\n <bubble-menu v-if=\"editor\" :editor=\"editor\" :should-show=\"bubbleShouldShow\">\n <div class=\"rtf-bubble-menu\">\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.bold\" @click=\"toggle('toggleBold')\">\n <cached-icon name=\"mdi-format-bold\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.italic\" @click=\"toggle('toggleItalic')\">\n <cached-icon name=\"mdi-format-italic\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.link\" @click=\"toggleBubbleLink\">\n <cached-icon name=\"mdi-link-variant\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.bulletList\" @click=\"toggle('toggleBulletList')\">\n <cached-icon name=\"mdi-format-list-bulleted\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.orderedList\" @click=\"toggle('toggleOrderedList')\">\n <cached-icon name=\"mdi-format-list-numbered\" />\n </v-btn>\n </div>\n </bubble-menu>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Image from '@tiptap/extension-image';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { Table } from '@tiptap/extension-table';\nimport TableCell from '@tiptap/extension-table-cell';\nimport TableHeader from '@tiptap/extension-table-header';\nimport TableRow from '@tiptap/extension-table-row';\nimport TextAlign from '@tiptap/extension-text-align';\nimport { NodeSelection } from '@tiptap/pm/state';\nimport StarterKit from '@tiptap/starter-kit';\nimport { EditorContent, useEditor } from '@tiptap/vue-3';\nimport { BubbleMenu } from '@tiptap/vue-3/menus';\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { VuetifyButtonSize } from '../input-base';\nimport { translatableStrings } from '../translations';\n\nimport { ClassAttribute, Marker, Spoiler } from './block-styles';\nimport { createImagePasteHandler } from './image-paste';\nimport { LinkWithDownload } from './link-with-download';\nimport { MediaEmbed } from './media-embed';\nimport RtfToolbar from './rtf-toolbar.vue';\nimport { useEditorTick } from './use-editor-tick';\nimport { stripWordArtifacts } from './word-paste';\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string;\n minHeight?: string;\n disabled?: boolean;\n toolbarButtonSize?: VuetifyButtonSize;\n fontFamily?: string;\n }>(),\n { modelValue: '', minHeight: '7em', disabled: false, toolbarButtonSize: 'small', fontFamily: 'inherit' },\n);\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void;\n}>();\n\n// `<df-rtf-editor>`'s label is positioned by a fixed `translate()` in its own stylesheet, tuned around a\n// single-row toolbar - it has no other way to know the toolbar's actual height, since the label (drawn by\n// `v-field`'s `#label` slot) and the toolbar (drawn by this component, inside `v-field`'s default slot) are\n// siblings, not ancestor/descendant. Publishing the toolbar's measured height as a CSS custom property on their\n// shared `.v-field` ancestor lets that `translate()` read a real value instead of guessing one - it still needs\n// to reach up past this component's own root to a DOM node it doesn't otherwise touch, which is what the\n// `.closest()` below is for.\nconst toolbarRef = ref<InstanceType<typeof RtfToolbar>>();\nlet toolbarResizeObserver: ResizeObserver | undefined;\n\nonMounted(() => {\n const toolbarEl = toolbarRef.value?.$el as HTMLElement | undefined;\n const fieldEl = toolbarEl?.closest<HTMLElement>('.v-field');\n if (!toolbarEl || !fieldEl) return;\n toolbarResizeObserver = new ResizeObserver(([entry]) => {\n fieldEl.style.setProperty('--rtf-toolbar-height', `${entry.contentRect.height}px`);\n });\n toolbarResizeObserver.observe(toolbarEl);\n});\nonBeforeUnmount(() => toolbarResizeObserver?.disconnect());\n\nconst editor = useEditor({\n content: props.modelValue,\n editable: !props.disabled,\n extensions: [\n StarterKit.configure({ link: false }),\n LinkWithDownload.configure({ openOnClick: false, autolink: true, defaultProtocol: 'https' }),\n Image.configure({\n inline: true,\n allowBase64: true,\n resize: {\n enabled: true,\n directions: ['top', 'right', 'bottom', 'left', 'top-left', 'top-right', 'bottom-left', 'bottom-right'],\n minWidth: 24,\n minHeight: 24,\n },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Table.configure({ resizable: true }),\n TableRow,\n TableHeader,\n TableCell,\n Placeholder.configure({ placeholder: '' }),\n ClassAttribute,\n Marker,\n Spoiler,\n MediaEmbed,\n ],\n editorProps: {\n attributes: { class: 'rtf-content' },\n transformPastedHTML: (html: string) => stripWordArtifacts(html),\n handlePaste: createImagePasteHandler(() => editor.value),\n },\n // ProseMirror's schema never lets the document itself be empty - a cleared editor still holds one empty\n // paragraph, whose serialized HTML is '<p></p>'. Emitting that instead of '' would make a `required` rule\n // checking for a falsy modelValue pass on a field the user never actually typed or pasted anything into.\n onUpdate: ({ editor: instance }) => {\n emit('update:modelValue', instance.isEmpty ? '' : instance.getHTML());\n },\n});\n\n// External writes (a reset, a different record loaded into the same form) are applied without re-emitting: the\n// third `setContent` argument suppresses the `update` this would otherwise trigger straight back out.\nwatch(\n () => props.modelValue,\n (value) => {\n const instance = editor.value;\n if (!instance) return;\n const incoming = value ?? '';\n if (incoming === instance.getHTML()) return;\n instance.commands.setContent(incoming, { emitUpdate: false });\n },\n);\n\nwatch(\n () => props.disabled,\n (disabled) => editor.value?.setEditable(!disabled),\n);\nwatch(editor, (instance) => instance?.setEditable(!props.disabled));\n\nconst bubbleButtonProps = { icon: true, size: 'small', density: 'comfortable', variant: 'text' } as const;\n\nconst bubbleTick = useEditorTick(editor);\nconst bubbleState = computed(() => {\n void bubbleTick.value;\n return {\n bold: !!editor.value?.isActive('bold'),\n italic: !!editor.value?.isActive('italic'),\n link: !!editor.value?.isActive('link'),\n bulletList: !!editor.value?.isActive('bulletList'),\n orderedList: !!editor.value?.isActive('orderedList'),\n };\n});\n\n// A NodeSelection (an image, a table, a horizontal rule - anything selected as a whole rather than as text) is\n// excluded: bold/italic/link/list toggles don't apply to a selected node, so showing this text-formatting bubble\n// over one is just noise sitting on top of whatever selection UI that node has of its own (an image's resize\n// handles, for instance).\nfunction bubbleShouldShow({ state }: { state: { selection: { empty: boolean } } }) {\n return !state.selection.empty && !(state.selection instanceof NodeSelection);\n}\n\nfunction toggle(command: 'toggleBold' | 'toggleItalic' | 'toggleBulletList' | 'toggleOrderedList') {\n editor.value?.chain().focus()[command]().run();\n}\n\nfunction toggleBubbleLink() {\n const instance = editor.value;\n if (!instance) return;\n if (instance.isActive('link')) {\n instance.chain().focus().unsetLink().run();\n return;\n }\n\n const href = window.prompt(translatableStrings.LinkUrl);\n if (href) instance.chain().focus().extendMarkRange('link').setLink({ href }).run();\n}\n</script>\n\n<style>\n@media print {\n body {\n margin: 0 !important;\n }\n}\n\n.editor-container {\n font-family: v-bind(fontFamily);\n width: 100%;\n}\n\n.rtf-content {\n line-height: 1.6;\n word-break: break-word;\n min-height: v-bind(minHeight);\n padding: 0.5em 0.75em;\n background: rgb(var(--v-theme-surface));\n color: rgb(var(--v-theme-on-surface));\n outline: none;\n}\n\n.rtf-content p {\n margin: 0 0 1em;\n}\n\n/* ProseMirror's list/table schemas wrap every block of text in a <p>, list item or cell content included, so\n without this every list item and table cell would carry the same margin ordinary paragraphs do - list items\n readable as double-spaced lines, cells with dead space above and below their text. */\n.rtf-content li p,\n.rtf-content td p,\n.rtf-content th p {\n margin: 0;\n}\n\n.rtf-content li + li {\n margin-top: 0;\n}\n\n.rtf-content img {\n max-width: 100%;\n height: auto;\n}\n\n/* TipTap's image resize NodeView (@tiptap/extension-image's `resize` option) builds the handle elements below\n with no visual styling of their own - position only - so the consuming app is expected to supply the look. */\n.rtf-content [data-resize-handle] {\n background: rgb(var(--v-theme-primary));\n border: 1px solid rgb(var(--v-theme-surface));\n border-radius: 2px;\n opacity: 0;\n transition: opacity 0.1s ease;\n z-index: 1;\n}\n\n.rtf-content [data-resize-container]:hover [data-resize-handle],\n.rtf-content [data-resize-container]:focus-within [data-resize-handle] {\n opacity: 1;\n}\n\n.rtf-content [data-resize-handle='top'],\n.rtf-content [data-resize-handle='bottom'] {\n height: 6px;\n cursor: ns-resize;\n}\n\n.rtf-content [data-resize-handle='left'],\n.rtf-content [data-resize-handle='right'] {\n width: 6px;\n cursor: ew-resize;\n}\n\n.rtf-content [data-resize-handle='top-left'],\n.rtf-content [data-resize-handle='bottom-right'] {\n width: 10px;\n height: 10px;\n cursor: nwse-resize;\n}\n\n.rtf-content [data-resize-handle='top-right'],\n.rtf-content [data-resize-handle='bottom-left'] {\n width: 10px;\n height: 10px;\n cursor: nesw-resize;\n}\n\n/* Holding Shift while dragging a handle locks the aspect ratio (ResizableNodeView's own behaviour, not\n something this component adds) - a one-off tooltip on the corner handle most people reach for first is enough\n to surface it, rather than a whole toolbar for a modifier key. */\n.rtf-content [data-resize-handle='bottom-right']:hover::after {\n content: 'Hold Shift to keep the aspect ratio';\n position: absolute;\n bottom: 14px;\n right: 0;\n white-space: nowrap;\n font-size: 12px;\n padding: 2px 6px;\n border-radius: 4px;\n background: rgb(var(--v-theme-surface-variant));\n color: rgb(var(--v-theme-on-surface-variant));\n pointer-events: none;\n}\n\n.rtf-content iframe.media-embed {\n width: 100%;\n aspect-ratio: 16 / 9;\n margin: 1em 0;\n border: 0;\n}\n\n.rtf-bubble-menu {\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 2px;\n background: rgb(var(--v-theme-surface));\n border: 1px solid rgb(var(--v-theme-surface-variant));\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n}\n\n.rtf-content h3.category {\n font-size: 20px;\n font-weight: bold;\n color: #555;\n letter-spacing: 10px;\n margin: 0;\n padding: 0;\n}\n\n.rtf-content h2.document-title {\n font-size: 50px;\n font-weight: bold;\n margin: 0;\n padding: 0;\n border: 0;\n}\n\n.rtf-content h3.document-subtitle {\n font-size: 20px;\n color: #555;\n margin: 0 0 1em;\n font-weight: bold;\n padding: 0;\n}\n\n.rtf-content p.info-box {\n --background-size: 30px;\n --background-color: #e91e63;\n padding: 1.2em 2em;\n border: 1px solid var(--background-color);\n background:\n linear-gradient(\n 135deg,\n var(--background-color) 0%,\n var(--background-color) var(--background-size),\n transparent var(--background-size)\n ),\n linear-gradient(\n 135deg,\n transparent calc(100% - var(--background-size)),\n var(--background-color) calc(100% - var(--background-size)),\n var(--background-color)\n );\n border-radius: 10px;\n margin: 1.5em 2em;\n box-shadow: 5px 5px 0 #ffe6ef;\n}\n\n.rtf-content blockquote.side-quote {\n font-style: normal;\n float: right;\n width: 35%;\n position: relative;\n border: 0;\n overflow: visible;\n z-index: 1;\n margin-left: 1em;\n}\n\n.rtf-content blockquote.side-quote::before {\n content: '“';\n position: absolute;\n top: -37px;\n left: -10px;\n display: block;\n font-size: 200px;\n color: #e7e7e7;\n z-index: -1;\n line-height: 1;\n}\n\n.rtf-content blockquote.side-quote p {\n font-size: 2em;\n line-height: 1;\n}\n\n.rtf-content blockquote.side-quote p:last-child:not(:first-child) {\n font-size: 1.3em;\n text-align: right;\n color: #555;\n}\n\n.rtf-content span.marker {\n background: yellow;\n}\n\n.rtf-content span.spoiler {\n background: #000;\n color: #000;\n}\n\n.rtf-content span.spoiler:hover {\n background: #000;\n color: #fff;\n}\n\n.rtf-content pre.fancy-code {\n border: 0;\n margin-left: 2em;\n margin-right: 2em;\n border-radius: 10px;\n}\n\n.rtf-content pre.fancy-code::before {\n content: '';\n display: block;\n height: 13px;\n background: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NCAxMyI+CiAgPGNpcmNsZSBjeD0iNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGMzZCNUMiLz4KICA8Y2lyY2xlIGN4PSIyNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGOUJFNEQiLz4KICA8Y2lyY2xlIGN4PSI0Ny41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiM1NkM0NTMiLz4KPC9zdmc+Cg==);\n margin-bottom: 8px;\n background-repeat: no-repeat;\n}\n\n.rtf-content pre.fancy-code-dark {\n background: #272822;\n color: #fff;\n box-shadow: 5px 5px 0 #0000001f;\n}\n\n.rtf-content pre.fancy-code-bright {\n background: #dddfe0;\n color: #000;\n box-shadow: 5px 5px 0 #b3b3b3;\n}\n</style>\n","<template>\n <div class=\"editor-container\">\n <rtf-toolbar ref=\"toolbarRef\" :editor=\"editor\" :button-size=\"toolbarButtonSize\" />\n <editor-content class=\"editor-container__editor\" :editor=\"editor\" />\n <bubble-menu v-if=\"editor\" :editor=\"editor\" :should-show=\"bubbleShouldShow\">\n <div class=\"rtf-bubble-menu\">\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.bold\" @click=\"toggle('toggleBold')\">\n <cached-icon name=\"mdi-format-bold\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.italic\" @click=\"toggle('toggleItalic')\">\n <cached-icon name=\"mdi-format-italic\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.link\" @click=\"toggleBubbleLink\">\n <cached-icon name=\"mdi-link-variant\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.bulletList\" @click=\"toggle('toggleBulletList')\">\n <cached-icon name=\"mdi-format-list-bulleted\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.orderedList\" @click=\"toggle('toggleOrderedList')\">\n <cached-icon name=\"mdi-format-list-numbered\" />\n </v-btn>\n </div>\n </bubble-menu>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Image from '@tiptap/extension-image';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { Table } from '@tiptap/extension-table';\nimport TableCell from '@tiptap/extension-table-cell';\nimport TableHeader from '@tiptap/extension-table-header';\nimport TableRow from '@tiptap/extension-table-row';\nimport TextAlign from '@tiptap/extension-text-align';\nimport { NodeSelection } from '@tiptap/pm/state';\nimport StarterKit from '@tiptap/starter-kit';\nimport { EditorContent, useEditor } from '@tiptap/vue-3';\nimport { BubbleMenu } from '@tiptap/vue-3/menus';\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { VuetifyButtonSize } from '../input-base';\nimport { translatableStrings } from '../translations';\n\nimport { ClassAttribute, Marker, Spoiler } from './block-styles';\nimport { createImagePasteHandler } from './image-paste';\nimport { LinkWithDownload } from './link-with-download';\nimport { MediaEmbed } from './media-embed';\nimport RtfToolbar from './rtf-toolbar.vue';\nimport { useEditorTick } from './use-editor-tick';\nimport { stripWordArtifacts } from './word-paste';\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string;\n minHeight?: string;\n disabled?: boolean;\n toolbarButtonSize?: VuetifyButtonSize;\n fontFamily?: string;\n }>(),\n { modelValue: '', minHeight: '7em', disabled: false, toolbarButtonSize: 'small', fontFamily: 'inherit' },\n);\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void;\n}>();\n\n// `<df-rtf-editor>`'s label is positioned by a fixed `translate()` in its own stylesheet, tuned around a\n// single-row toolbar - it has no other way to know the toolbar's actual height, since the label (drawn by\n// `v-field`'s `#label` slot) and the toolbar (drawn by this component, inside `v-field`'s default slot) are\n// siblings, not ancestor/descendant. Publishing the toolbar's measured height as a CSS custom property on their\n// shared `.v-field` ancestor lets that `translate()` read a real value instead of guessing one - it still needs\n// to reach up past this component's own root to a DOM node it doesn't otherwise touch, which is what the\n// `.closest()` below is for.\nconst toolbarRef = ref<InstanceType<typeof RtfToolbar>>();\nlet toolbarResizeObserver: ResizeObserver | undefined;\n\nonMounted(() => {\n const toolbarEl = toolbarRef.value?.$el as HTMLElement | undefined;\n const fieldEl = toolbarEl?.closest<HTMLElement>('.v-field');\n if (!toolbarEl || !fieldEl) return;\n toolbarResizeObserver = new ResizeObserver(([entry]) => {\n fieldEl.style.setProperty('--rtf-toolbar-height', `${entry.contentRect.height}px`);\n });\n toolbarResizeObserver.observe(toolbarEl);\n});\nonBeforeUnmount(() => toolbarResizeObserver?.disconnect());\n\nconst editor = useEditor({\n content: props.modelValue,\n editable: !props.disabled,\n extensions: [\n StarterKit.configure({ link: false }),\n LinkWithDownload.configure({ openOnClick: false, autolink: true, defaultProtocol: 'https' }),\n Image.configure({\n inline: true,\n allowBase64: true,\n resize: {\n enabled: true,\n directions: ['top', 'right', 'bottom', 'left', 'top-left', 'top-right', 'bottom-left', 'bottom-right'],\n minWidth: 24,\n minHeight: 24,\n },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Table.configure({ resizable: true }),\n TableRow,\n TableHeader,\n TableCell,\n Placeholder.configure({ placeholder: '' }),\n ClassAttribute,\n Marker,\n Spoiler,\n MediaEmbed,\n ],\n editorProps: {\n attributes: { class: 'rtf-content' },\n transformPastedHTML: (html: string) => stripWordArtifacts(html),\n handlePaste: createImagePasteHandler(() => editor.value),\n },\n // ProseMirror's schema never lets the document itself be empty - a cleared editor still holds one empty\n // paragraph, whose serialized HTML is '<p></p>'. Emitting that instead of '' would make a `required` rule\n // checking for a falsy modelValue pass on a field the user never actually typed or pasted anything into.\n onUpdate: ({ editor: instance }) => {\n emit('update:modelValue', instance.isEmpty ? '' : instance.getHTML());\n },\n});\n\n// External writes (a reset, a different record loaded into the same form) are applied without re-emitting: the\n// third `setContent` argument suppresses the `update` this would otherwise trigger straight back out.\nwatch(\n () => props.modelValue,\n (value) => {\n const instance = editor.value;\n if (!instance) return;\n const incoming = value ?? '';\n if (incoming === instance.getHTML()) return;\n instance.commands.setContent(incoming, { emitUpdate: false });\n },\n);\n\nwatch(\n () => props.disabled,\n (disabled) => editor.value?.setEditable(!disabled),\n);\nwatch(editor, (instance) => instance?.setEditable(!props.disabled));\n\nconst bubbleButtonProps = { icon: true, size: 'small', density: 'comfortable', variant: 'text' } as const;\n\nconst bubbleTick = useEditorTick(editor);\nconst bubbleState = computed(() => {\n void bubbleTick.value;\n return {\n bold: !!editor.value?.isActive('bold'),\n italic: !!editor.value?.isActive('italic'),\n link: !!editor.value?.isActive('link'),\n bulletList: !!editor.value?.isActive('bulletList'),\n orderedList: !!editor.value?.isActive('orderedList'),\n };\n});\n\n// A NodeSelection (an image, a table, a horizontal rule - anything selected as a whole rather than as text) is\n// excluded: bold/italic/link/list toggles don't apply to a selected node, so showing this text-formatting bubble\n// over one is just noise sitting on top of whatever selection UI that node has of its own (an image's resize\n// handles, for instance).\nfunction bubbleShouldShow({ state }: { state: { selection: { empty: boolean } } }) {\n return !state.selection.empty && !(state.selection instanceof NodeSelection);\n}\n\nfunction toggle(command: 'toggleBold' | 'toggleItalic' | 'toggleBulletList' | 'toggleOrderedList') {\n editor.value?.chain().focus()[command]().run();\n}\n\nfunction toggleBubbleLink() {\n const instance = editor.value;\n if (!instance) return;\n if (instance.isActive('link')) {\n instance.chain().focus().unsetLink().run();\n return;\n }\n\n const href = window.prompt(translatableStrings.LinkUrl);\n if (href) instance.chain().focus().extendMarkRange('link').setLink({ href }).run();\n}\n</script>\n\n<style>\n@media print {\n body {\n margin: 0 !important;\n }\n}\n\n.editor-container {\n font-family: v-bind(fontFamily);\n width: 100%;\n}\n\n.rtf-content {\n line-height: 1.6;\n word-break: break-word;\n min-height: v-bind(minHeight);\n padding: 0.5em 0.75em;\n background: rgb(var(--v-theme-surface));\n color: rgb(var(--v-theme-on-surface));\n outline: none;\n}\n\n.rtf-content p {\n margin: 0 0 1em;\n}\n\n/* ProseMirror's list/table schemas wrap every block of text in a <p>, list item or cell content included, so\n without this every list item and table cell would carry the same margin ordinary paragraphs do - list items\n readable as double-spaced lines, cells with dead space above and below their text. */\n.rtf-content li p,\n.rtf-content td p,\n.rtf-content th p {\n margin: 0;\n}\n\n.rtf-content li + li {\n margin-top: 0;\n}\n\n.rtf-content img {\n max-width: 100%;\n height: auto;\n}\n\n/* TipTap's image resize NodeView (@tiptap/extension-image's `resize` option) builds the handle elements below\n with no visual styling of their own - position only - so the consuming app is expected to supply the look. */\n.rtf-content [data-resize-handle] {\n background: rgb(var(--v-theme-primary));\n border: 1px solid rgb(var(--v-theme-surface));\n border-radius: 2px;\n opacity: 0;\n transition: opacity 0.1s ease;\n z-index: 1;\n}\n\n.rtf-content [data-resize-container]:hover [data-resize-handle],\n.rtf-content [data-resize-container]:focus-within [data-resize-handle] {\n opacity: 1;\n}\n\n.rtf-content [data-resize-handle='top'],\n.rtf-content [data-resize-handle='bottom'] {\n height: 6px;\n cursor: ns-resize;\n}\n\n.rtf-content [data-resize-handle='left'],\n.rtf-content [data-resize-handle='right'] {\n width: 6px;\n cursor: ew-resize;\n}\n\n.rtf-content [data-resize-handle='top-left'],\n.rtf-content [data-resize-handle='bottom-right'] {\n width: 10px;\n height: 10px;\n cursor: nwse-resize;\n}\n\n.rtf-content [data-resize-handle='top-right'],\n.rtf-content [data-resize-handle='bottom-left'] {\n width: 10px;\n height: 10px;\n cursor: nesw-resize;\n}\n\n/* Holding Shift while dragging a handle locks the aspect ratio (ResizableNodeView's own behaviour, not\n something this component adds) - a one-off tooltip on the corner handle most people reach for first is enough\n to surface it, rather than a whole toolbar for a modifier key. */\n.rtf-content [data-resize-handle='bottom-right']:hover::after {\n content: 'Hold Shift to keep the aspect ratio';\n position: absolute;\n bottom: 14px;\n right: 0;\n white-space: nowrap;\n font-size: 12px;\n padding: 2px 6px;\n border-radius: 4px;\n background: rgb(var(--v-theme-surface-variant));\n color: rgb(var(--v-theme-on-surface-variant));\n pointer-events: none;\n}\n\n.rtf-content iframe.media-embed {\n width: 100%;\n aspect-ratio: 16 / 9;\n margin: 1em 0;\n border: 0;\n}\n\n.rtf-bubble-menu {\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 2px;\n background: rgb(var(--v-theme-surface));\n border: 1px solid rgb(var(--v-theme-surface-variant));\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n}\n\n.rtf-content h3.category {\n font-size: 20px;\n font-weight: bold;\n color: #555;\n letter-spacing: 10px;\n margin: 0;\n padding: 0;\n}\n\n.rtf-content h2.document-title {\n font-size: 50px;\n font-weight: bold;\n margin: 0;\n padding: 0;\n border: 0;\n}\n\n.rtf-content h3.document-subtitle {\n font-size: 20px;\n color: #555;\n margin: 0 0 1em;\n font-weight: bold;\n padding: 0;\n}\n\n.rtf-content p.info-box {\n --background-size: 30px;\n --background-color: #e91e63;\n padding: 1.2em 2em;\n border: 1px solid var(--background-color);\n background:\n linear-gradient(\n 135deg,\n var(--background-color) 0%,\n var(--background-color) var(--background-size),\n transparent var(--background-size)\n ),\n linear-gradient(\n 135deg,\n transparent calc(100% - var(--background-size)),\n var(--background-color) calc(100% - var(--background-size)),\n var(--background-color)\n );\n border-radius: 10px;\n margin: 1.5em 2em;\n box-shadow: 5px 5px 0 #ffe6ef;\n}\n\n.rtf-content blockquote.side-quote {\n font-style: normal;\n float: right;\n width: 35%;\n position: relative;\n border: 0;\n overflow: visible;\n z-index: 1;\n margin-left: 1em;\n}\n\n.rtf-content blockquote.side-quote::before {\n content: '“';\n position: absolute;\n top: -37px;\n left: -10px;\n display: block;\n font-size: 200px;\n color: #e7e7e7;\n z-index: -1;\n line-height: 1;\n}\n\n.rtf-content blockquote.side-quote p {\n font-size: 2em;\n line-height: 1;\n}\n\n.rtf-content blockquote.side-quote p:last-child:not(:first-child) {\n font-size: 1.3em;\n text-align: right;\n color: #555;\n}\n\n.rtf-content span.marker {\n background: yellow;\n}\n\n.rtf-content span.spoiler {\n background: #000;\n color: #000;\n}\n\n.rtf-content span.spoiler:hover {\n background: #000;\n color: #fff;\n}\n\n.rtf-content pre.fancy-code {\n border: 0;\n margin-left: 2em;\n margin-right: 2em;\n border-radius: 10px;\n}\n\n.rtf-content pre.fancy-code::before {\n content: '';\n display: block;\n height: 13px;\n background: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NCAxMyI+CiAgPGNpcmNsZSBjeD0iNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGMzZCNUMiLz4KICA8Y2lyY2xlIGN4PSIyNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGOUJFNEQiLz4KICA8Y2lyY2xlIGN4PSI0Ny41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiM1NkM0NTMiLz4KPC9zdmc+Cg==);\n margin-bottom: 8px;\n background-repeat: no-repeat;\n}\n\n.rtf-content pre.fancy-code-dark {\n background: #272822;\n color: #fff;\n box-shadow: 5px 5px 0 #0000001f;\n}\n\n.rtf-content pre.fancy-code-bright {\n background: #dddfe0;\n color: #000;\n box-shadow: 5px 5px 0 #b3b3b3;\n}\n</style>\n","<template>\n <input-base v-bind=\"props\" class=\"rtf-editor\" :class=\"densityClass\">\n <template #default=\"slotProps\">\n <rtf-editor-core\n ref=\"$editor\"\n v-model=\"value\"\n :class=\"{ 'mt-6': !!label }\"\n :min-height=\"minHeight\"\n :disabled=\"vuetifyBindings.disabled\"\n :toolbar-button-size=\"toolbarButtonSize\"\n :font-family=\"fontFamily\"\n v-bind=\"passthroughAttrs\"\n @focusin=\"slotProps.focus()\"\n @focusout=\"slotProps.blur()\"\n />\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { DfRtfEditorProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, InputBase, useInputBase } from './helpers';\nimport RtfEditorCore from './helpers/rtf-editor/editor-core.vue';\n\nconst props = withDefaults(defineProps<DfRtfEditorProps>(), { ...defaultBaseProps, minHeight: undefined });\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, value, vuetifyBindings } = useInputBase(props, emits);\n</script>\n\n<style>\n.rtf-editor .v-field:not(.v-field--active) .v-label.v-field-label:not(.v-field-label--floating) {\n /* `--rtf-toolbar-height` is set by editor-core.vue's own `ResizeObserver`, straight onto this `.v-field`; the\n 3em fallback only matters before that first measurement lands or if it never does (a non-browser render).\n The added 0.5em is the gap between the toolbar's bottom edge and the label's own baseline - without it the\n label sits flush against the toolbar instead of inside the content area's padding. */\n transform: translate(0.5em, calc(var(--rtf-toolbar-height, 3em) + 1em));\n}\n\n.rtf-editor .v-input__control {\n /* So the toolbar's dropdown menus draw over vuetify inputs that are positioned underneath */\n z-index: 1;\n}\n</style>\n","<template>\n <input-base v-bind=\"props\" class=\"rtf-editor\" :class=\"densityClass\">\n <template #default=\"slotProps\">\n <rtf-editor-core\n ref=\"$editor\"\n v-model=\"value\"\n :class=\"{ 'mt-6': !!label }\"\n :min-height=\"minHeight\"\n :disabled=\"vuetifyBindings.disabled\"\n :toolbar-button-size=\"toolbarButtonSize\"\n :font-family=\"fontFamily\"\n v-bind=\"passthroughAttrs\"\n @focusin=\"slotProps.focus()\"\n @focusout=\"slotProps.blur()\"\n />\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { DfRtfEditorProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, InputBase, useInputBase } from './helpers';\nimport RtfEditorCore from './helpers/rtf-editor/editor-core.vue';\n\nconst props = withDefaults(defineProps<DfRtfEditorProps>(), { ...defaultBaseProps, minHeight: undefined });\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, value, vuetifyBindings } = useInputBase(props, emits);\n</script>\n\n<style>\n.rtf-editor .v-field:not(.v-field--active) .v-label.v-field-label:not(.v-field-label--floating) {\n /* `--rtf-toolbar-height` is set by editor-core.vue's own `ResizeObserver`, straight onto this `.v-field`; the\n 3em fallback only matters before that first measurement lands or if it never does (a non-browser render).\n The added 0.5em is the gap between the toolbar's bottom edge and the label's own baseline - without it the\n label sits flush against the toolbar instead of inside the content area's padding. */\n transform: translate(0.5em, calc(var(--rtf-toolbar-height, 3em) + 1em));\n}\n\n.rtf-editor .v-input__control {\n /* So the toolbar's dropdown menus draw over vuetify inputs that are positioned underneath */\n z-index: 1;\n}\n</style>\n","import { isArray, first, castArray } from 'lodash-es';\nimport { Ref } from 'vue';\n\nimport { SelectChoice } from './df-select.interface';\n\nexport function convertItems(items: SelectChoice[]) {\n return items.map((item) => ({ value: item.id, title: item.text, icon: item.icon }));\n}\n\n/**\n * multipleCompliantValue ensures that resulting value of the select component is\n * 1 - null, when nothing is selected\n * 2 - array, when multiple is truthy\n * 3 - ordinal / simple value when multiple is not truthy\n * @param value the value to make compliant\n * @param multiple indicator for multiple selection\n */\nexport function multipleCompliantValue(value: any, multiple: boolean): any {\n // Če je vrednost null ali undefined\n if (value == null) return null;\n\n // Če je prazno polje (za multiple)\n if (isArray(value) && value.length === 0) return null;\n\n // Za multiple vedno vrni polje\n if (multiple) return castArray(value);\n\n // Za single vrni prvo vrednost ali vrednost samo\n return isArray(value) ? (first(value) ?? null) : value;\n}\n\nexport function getSelectedChoices(loadedChoices: SelectChoice[], multipleCpliantValue: any | any[] | null) {\n if (multipleCpliantValue == null) return [];\n const mcValue = castArray(multipleCpliantValue);\n return loadedChoices.filter((choice) => mcValue.some((val: any) => val === choice.id));\n}\n\n/**\n * updateSelectedFromValue ensures that the actual select component receives model-value formatted to its needs\n */\nexport function updateSelectedFromValue(\n resultingValue: any,\n selected: Ref<any>,\n multiple: boolean,\n taggable: boolean,\n loadedChoices: SelectChoice[],\n) {\n const mcValue = multipleCompliantValue(resultingValue, multiple);\n\n if (mcValue == null) {\n selected.value = multiple ? [] : null;\n return;\n }\n\n if (multiple) {\n if (taggable) {\n // if taggable (can add new items not in choices), keep the value as-is\n selected.value = mcValue;\n } else {\n // when not taggable, we filter the result to existing choices\n selected.value = getSelectedChoices(loadedChoices, mcValue).map((choice) => choice.id);\n }\n } else {\n if (taggable) {\n // if taggable, we just keep the selected value\n selected.value = mcValue;\n } else {\n // when not taggable, we filter the result to existing choices\n const matchingChoice = first(getSelectedChoices(loadedChoices, mcValue));\n selected.value = matchingChoice?.id ?? null;\n }\n }\n}\n","<template>\n <component\n :is=\"taggable ? 'v-combobox' : 'v-autocomplete'\"\n v-if=\"isRendered\"\n ref=\"dfSelectRef\"\n v-model=\"selected\"\n :class=\"[cssClass, densityClass, visibilityClass, { 'df-select-multirow': isMultiline }]\"\n :items=\"options\"\n :return-object=\"false\"\n chips\n :auto-select-first=\"true\"\n :closable-chips=\"allowNull || (multiple && selected.length > 1)\"\n :clearable=\"allowNull\"\n :multiple=\"multiple\"\n :loading=\"loading\"\n :hide-selected=\"false\"\n :aria-describedby=\"vuetifyBindings.helpText ? `${vuetifyBindings.name}-help` : null\"\n :menu-props=\"{ maxHeight: '400' }\"\n :search=\"searchText\"\n v-bind=\"vuetifyBindings\"\n @update:search=\"(query: any) => queryOptions(query, undefined)\"\n @update:model-value=\"onSelect\"\n @click:clear=\"selected = null\"\n @blur=\"touched = true\"\n @mousedown.capture=\"onMouseDown($event)\"\n >\n <template #chip=\"{ item }\">\n <v-chip\n :key=\"item.value\"\n label\n size=\"small\"\n class=\"d-flex align-middle\"\n :variant=\"multiple ? 'tonal' : 'text'\"\n :closable=\"multiple\"\n @click:close=\"chipClose($event, item.value)\"\n >\n <template #prepend>\n <cached-icon v-if=\"item.raw?.icon\" class=\"me-1\" :name=\"item.raw.icon\" />\n </template>\n <span :class=\"{ 'text-body-1': !multiple }\">{{ item.title }}</span>\n </v-chip>\n </template>\n <template #label=\"labelData\">\n <df-label :data=\"labelData\" :label=\"label\" />\n </template>\n\n <template #item=\"{ props: prps, item }\">\n <v-list-item v-bind=\"prps\">\n <template #prepend>\n <span v-if=\"item.raw?.icon\" class=\"me-1\">\n <cached-icon class=\"action-icon\" :name=\"item.raw.icon\" />\n </span>\n </template>\n </v-list-item>\n </template>\n <template #message=\"{ message }\">\n <df-input-hint :message=\"message\" :errors=\"showErrors\" />\n </template>\n <template v-if=\"$slots['append-inner']\" #append-inner=\"props\">\n <slot name=\"append-inner\" v-bind=\"props\" />\n </template>\n <template v-if=\"$slots['prepend-inner']\" #prepend-inner=\"props\">\n <slot name=\"prepend-inner\" v-bind=\"props\" />\n </template>\n </component>\n</template>\n\n<script setup lang=\"ts\">\nimport { castArray, isEqual, unionBy } from 'lodash-es';\nimport { computed, nextTick, ref, toRefs, unref, watch } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\nimport { VAutocomplete, VCombobox } from 'vuetify/components';\n\nimport { DfSelectProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, SelectChoice, useInputBase } from './helpers';\nimport {\n convertItems,\n getSelectedChoices,\n multipleCompliantValue,\n updateSelectedFromValue,\n} from './helpers/df-select.helper';\n\nconst propsWithDefaults = withDefaults(defineProps<DfSelectProps>(), {\n ...defaultBaseProps,\n choices: undefined,\n multiple: false,\n allowTags: false,\n allowNull: true,\n fetchChoices: undefined,\n});\n\nconst { choices, multiple, allowTags: taggable, allowNull, cssClass } = toRefs(propsWithDefaults);\n\ninterface Emits extends BaseEmits {\n (e: 'update:modelValueDisplay', value: SelectChoice[]): any;\n}\n\nconst emits = defineEmits<Emits>();\ndefineSlots<{\n 'append-inner'?: (props: any) => any;\n 'prepend-inner'?: (props: any) => any;\n}>();\n\nconst dfSelectRef = ref<InstanceType<typeof VAutocomplete> | InstanceType<typeof VCombobox> | null>(null);\n\nconst {\n densityClass,\n isRendered,\n label,\n showErrors,\n touched,\n value: resultingValue,\n visibilityClass,\n vuetifyBindings,\n} = useInputBase(propsWithDefaults, emits);\n\nconst selected = ref<any>(null);\nconst takeLoaded = ref(false);\nconst loaded = ref<SelectChoice[]>([]);\nconst loadedChoices = computed<SelectChoice[]>(() => (unref(takeLoaded) ? unref(loaded) : unref(choices) || []));\n\nconst options = computed(() => convertItems(loadedChoices.value));\nconst searchText = ref<string | null>(null);\nconst fetchCounterGlobal = ref(0);\nconst isMultiline = ref(false);\n// Number of fetchChoices calls in flight that resolve ids held by the value (resolveValueChoices()). While any is\n// pending, loadedChoices is not yet complete for the value, so `selected` - which only holds ids loadedChoices has a\n// choice for - is not written back into the value: that would drop every id still being resolved.\nconst resolvingValue = ref(0);\n// Number of queryOptions() calls in flight.\nconst searching = ref(0);\nconst loading = computed(() => searching.value > 0 || resolvingValue.value > 0);\n\nif (choices.value?.length && propsWithDefaults.fetchChoices !== undefined) {\n console.warn('Both choices and fetchChoices are set. Only one of them should be set.');\n}\n\nfunction emitModelValueDisplay(mcVal: any) {\n emits('update:modelValueDisplay', getSelectedChoices(loadedChoices.value, mcVal));\n}\n\nconst setResultingValueGuard = ref(false);\n\nfunction setResultingValue(newValue: any) {\n setResultingValueGuard.value = true;\n try {\n resultingValue.value = newValue;\n } finally {\n // The guard suppresses the watch that pushes the model's value back into `selected`. A write the control does\n // not take verbatim - a ValueChangedAction that writes another value back, a disabled field that drops it, a\n // handler that throws and unwinds it - never reaches that watch, so the chips would go on showing a selection\n // the control never took. Comparing what the control holds against what was written is what restores it, and\n // it needs a deep comparison: for multiple selection the value reads back as a different array holding the\n // same items. The comparison waits for the next tick: under v-model the parent passes the written value back as\n // modelValue only when it re-renders, and a read before that sees the previous value, reverts the selection and\n // emits it, which the parent passes back in turn - the two keep swapping values without end.\n nextTick(() => {\n const current = multipleCompliantValue(resultingValue.value, multiple.value);\n if (!isEqual(current, newValue)) {\n updateSelectedFromValue(current, selected, multiple.value, taggable.value, loadedChoices.value);\n }\n setResultingValueGuard.value = false;\n });\n }\n}\n\nfunction getFullWidth(item: HTMLElement | null) {\n if (!item) return 0;\n const rect = item.getBoundingClientRect();\n const style = window.getComputedStyle(item);\n\n return rect.width + parseFloat(style.marginLeft) + parseFloat(style.marginRight);\n}\n\nfunction checkMultiline() {\n if (multiple.value && allowNull.value && selected.value != null && selected.value.length > 0 && dfSelectRef.value) {\n const dfSelect = dfSelectRef.value.$el;\n const inputWidth = dfSelect.querySelector('.v-input__control')?.clientWidth;\n const container = dfSelect.querySelector('.v-field__input');\n const items = container.querySelectorAll('.v-autocomplete__selection, .v-combobox__selection');\n\n const style = window.getComputedStyle(container);\n let selectedWidth = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);\n\n items.forEach((item: HTMLElement) => {\n selectedWidth += getFullWidth(item);\n });\n\n const clearableWidth = getFullWidth(dfSelect.querySelector('.v-field .v-field__clearable'));\n const appendWidth = getFullWidth(dfSelect.querySelector('.v-field .v-field__append-inner'));\n const chipGap = 2;\n isMultiline.value = inputWidth - selectedWidth - items.length * chipGap - appendWidth < clearableWidth;\n } else {\n isMultiline.value = false;\n }\n}\n\nfunction onMouseDown(event: MouseEvent) {\n // če je klik na close ikoni ali njenem childu\n const target = event.target;\n if (target instanceof HTMLElement && target.closest('.v-chip__close')) {\n event.stopPropagation();\n event.preventDefault();\n }\n}\n\nwatch(\n selected,\n (newValue) => {\n if (vuetifyBindings.value.readonly || resolvingValue.value > 0) return;\n nextTick(() => {\n const mcVal = multipleCompliantValue(newValue, multiple.value);\n emitModelValueDisplay(mcVal);\n setResultingValue(mcVal);\n });\n },\n { deep: true },\n);\nwatch(\n resultingValue,\n (newValue: any) => {\n if (setResultingValueGuard.value) return;\n const mcVal = multipleCompliantValue(newValue, multiple.value);\n const resolved = resolveValueChoices(mcVal);\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n resolved?.then(() => {\n // A value set while this call was in flight started its own resolution and owns `selected` from then on.\n if (!isEqual(multipleCompliantValue(resultingValue.value, multiple.value), mcVal)) return;\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n });\n },\n { deep: true },\n);\n\nwatch(setResultingValueGuard, () => {\n if (!setResultingValueGuard.value) {\n checkMultiline();\n }\n});\n\nfunction resetQuery() {\n if (searchText.value != null && searchText.value.length > 0) {\n searchText.value = null;\n queryOptions();\n }\n}\n\nfunction onSelect(/* val: any */) {\n resetQuery();\n if (vuetifyBindings.value.readonly || taggable.value) return;\n const mcVal = multipleCompliantValue(selected.value, multiple.value);\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n setResultingValue(mcVal);\n}\n\nfunction chipClose(event: MouseEvent, itemValue: any) {\n event.stopPropagation();\n if (vuetifyBindings.value.readonly || taggable.value) {\n if (taggable.value) {\n selected.value = selected.value.filter((v: any) => v !== itemValue);\n }\n return;\n }\n let mcVal;\n if (multiple.value && Array.isArray(selected.value)) {\n mcVal = multipleCompliantValue(\n selected.value.filter((v) => v !== itemValue),\n multiple.value,\n );\n } else {\n mcVal = null;\n }\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n setResultingValue(mcVal);\n}\n\nasync function queryOptions(queryValue?: any, idValue?: any): Promise<void> {\n if (vuetifyBindings.value.readonly) return;\n searchText.value = queryValue;\n if (choices.value || propsWithDefaults.fetchChoices === undefined) return;\n const fetchCounter = ++fetchCounterGlobal.value;\n searching.value++;\n try {\n const newChoices = await propsWithDefaults.fetchChoices(queryValue, idValue);\n if (fetchCounter !== fetchCounterGlobal.value) return;\n // Taken after the fetch, from the value: choices resolveValueChoices() loaded while this call was in flight\n // must survive the search results replacing the rest.\n const selectedChoices = getSelectedChoices(\n loadedChoices.value,\n multipleCompliantValue(resultingValue.value, multiple.value),\n );\n loaded.value = unionBy([...selectedChoices, ...newChoices], 'id');\n takeLoaded.value = true;\n } finally {\n searching.value--;\n }\n}\n\n/**\n * Loads the choices for the ids in `mcVal` that loadedChoices has none for, through fetchChoices' idValue. Returns\n * null when there is nothing to load: no fetchChoices, a taggable select (its value is not limited to choices), or\n * every id already has its choice. An id fetchChoices returns no choice for stays without one, and the next\n * reconciliation against loadedChoices drops it from the value.\n */\nfunction resolveValueChoices(mcVal: any): Promise<void> | null {\n const fetchChoices = propsWithDefaults.fetchChoices;\n if (fetchChoices === undefined || taggable.value || mcVal == null) return null;\n const unresolved = castArray(mcVal).filter((val) => !loadedChoices.value.some((choice) => choice.id === val));\n if (!unresolved.length) return null;\n resolvingValue.value++;\n return (async () => {\n try {\n const newChoices = await fetchChoices(undefined, multiple.value ? unresolved : unresolved[0]);\n loaded.value = unionBy([...loadedChoices.value, ...newChoices], 'id');\n takeLoaded.value = true;\n } finally {\n resolvingValue.value--;\n }\n })();\n}\n\nfunction initialValueCheck() {\n let val = resultingValue.value;\n if (!allowNull.value && val == null && options.value.length) {\n // Starting settings: check if value is mandatory and select the first item from the options\n val = options.value[0].value;\n }\n val = multipleCompliantValue(val, multiple.value);\n updateSelectedFromValue(val, selected, multiple.value, taggable.value, loadedChoices.value);\n if (resolvingValue.value > 0) return;\n emitModelValueDisplay(val);\n setResultingValue(val);\n}\n\n// Starting settings: with fetchChoices, a value is first resolved into its choices and only then reconciled against\n// them. Anything else - an empty value, a taggable select - goes through queryOptions() with the value as idValue.\nlet initialLoad: Promise<void> | null = null;\nif (propsWithDefaults.fetchChoices !== undefined) {\n initialLoad =\n resolveValueChoices(multipleCompliantValue(resultingValue.value, multiple.value)) ??\n queryOptions(undefined, resultingValue.value);\n}\n\ninitialValueCheck();\n\ninitialLoad?.then(() => {\n initialValueCheck();\n});\n</script>\n\n<style scoped>\n.df-select-multirow :deep(.v-field__clearable) {\n position: absolute;\n}\n\n.df-select-multirow :deep(.v-field__append-inner) {\n margin-top: 24px;\n}\n\n.df-select-multirow :deep(.v-autocomplete .v-field:not(.v-field--focused) input) {\n min-width: 24px;\n}\n</style>\n","<template>\n <component\n :is=\"taggable ? 'v-combobox' : 'v-autocomplete'\"\n v-if=\"isRendered\"\n ref=\"dfSelectRef\"\n v-model=\"selected\"\n :class=\"[cssClass, densityClass, visibilityClass, { 'df-select-multirow': isMultiline }]\"\n :items=\"options\"\n :return-object=\"false\"\n chips\n :auto-select-first=\"true\"\n :closable-chips=\"allowNull || (multiple && selected.length > 1)\"\n :clearable=\"allowNull\"\n :multiple=\"multiple\"\n :loading=\"loading\"\n :hide-selected=\"false\"\n :aria-describedby=\"vuetifyBindings.helpText ? `${vuetifyBindings.name}-help` : null\"\n :menu-props=\"{ maxHeight: '400' }\"\n :search=\"searchText\"\n v-bind=\"vuetifyBindings\"\n @update:search=\"(query: any) => queryOptions(query, undefined)\"\n @update:model-value=\"onSelect\"\n @click:clear=\"selected = null\"\n @blur=\"touched = true\"\n @mousedown.capture=\"onMouseDown($event)\"\n >\n <template #chip=\"{ item }\">\n <v-chip\n :key=\"item.value\"\n label\n size=\"small\"\n class=\"d-flex align-middle\"\n :variant=\"multiple ? 'tonal' : 'text'\"\n :closable=\"multiple\"\n @click:close=\"chipClose($event, item.value)\"\n >\n <template #prepend>\n <cached-icon v-if=\"item.raw?.icon\" class=\"me-1\" :name=\"item.raw.icon\" />\n </template>\n <span :class=\"{ 'text-body-1': !multiple }\">{{ item.title }}</span>\n </v-chip>\n </template>\n <template #label=\"labelData\">\n <df-label :data=\"labelData\" :label=\"label\" />\n </template>\n\n <template #item=\"{ props: prps, item }\">\n <v-list-item v-bind=\"prps\">\n <template #prepend>\n <span v-if=\"item.raw?.icon\" class=\"me-1\">\n <cached-icon class=\"action-icon\" :name=\"item.raw.icon\" />\n </span>\n </template>\n </v-list-item>\n </template>\n <template #message=\"{ message }\">\n <df-input-hint :message=\"message\" :errors=\"showErrors\" />\n </template>\n <template v-if=\"$slots['append-inner']\" #append-inner=\"props\">\n <slot name=\"append-inner\" v-bind=\"props\" />\n </template>\n <template v-if=\"$slots['prepend-inner']\" #prepend-inner=\"props\">\n <slot name=\"prepend-inner\" v-bind=\"props\" />\n </template>\n </component>\n</template>\n\n<script setup lang=\"ts\">\nimport { castArray, isEqual, unionBy } from 'lodash-es';\nimport { computed, nextTick, ref, toRefs, unref, watch } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\nimport { VAutocomplete, VCombobox } from 'vuetify/components';\n\nimport { DfSelectProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, SelectChoice, useInputBase } from './helpers';\nimport {\n convertItems,\n getSelectedChoices,\n multipleCompliantValue,\n updateSelectedFromValue,\n} from './helpers/df-select.helper';\n\nconst propsWithDefaults = withDefaults(defineProps<DfSelectProps>(), {\n ...defaultBaseProps,\n choices: undefined,\n multiple: false,\n allowTags: false,\n allowNull: true,\n fetchChoices: undefined,\n});\n\nconst { choices, multiple, allowTags: taggable, allowNull, cssClass } = toRefs(propsWithDefaults);\n\ninterface Emits extends BaseEmits {\n (e: 'update:modelValueDisplay', value: SelectChoice[]): any;\n}\n\nconst emits = defineEmits<Emits>();\ndefineSlots<{\n 'append-inner'?: (props: any) => any;\n 'prepend-inner'?: (props: any) => any;\n}>();\n\nconst dfSelectRef = ref<InstanceType<typeof VAutocomplete> | InstanceType<typeof VCombobox> | null>(null);\n\nconst {\n densityClass,\n isRendered,\n label,\n showErrors,\n touched,\n value: resultingValue,\n visibilityClass,\n vuetifyBindings,\n} = useInputBase(propsWithDefaults, emits);\n\nconst selected = ref<any>(null);\nconst takeLoaded = ref(false);\nconst loaded = ref<SelectChoice[]>([]);\nconst loadedChoices = computed<SelectChoice[]>(() => (unref(takeLoaded) ? unref(loaded) : unref(choices) || []));\n\nconst options = computed(() => convertItems(loadedChoices.value));\nconst searchText = ref<string | null>(null);\nconst fetchCounterGlobal = ref(0);\nconst isMultiline = ref(false);\n// Number of fetchChoices calls in flight that resolve ids held by the value (resolveValueChoices()). While any is\n// pending, loadedChoices is not yet complete for the value, so `selected` - which only holds ids loadedChoices has a\n// choice for - is not written back into the value: that would drop every id still being resolved.\nconst resolvingValue = ref(0);\n// Number of queryOptions() calls in flight.\nconst searching = ref(0);\nconst loading = computed(() => searching.value > 0 || resolvingValue.value > 0);\n\nif (choices.value?.length && propsWithDefaults.fetchChoices !== undefined) {\n console.warn('Both choices and fetchChoices are set. Only one of them should be set.');\n}\n\nfunction emitModelValueDisplay(mcVal: any) {\n emits('update:modelValueDisplay', getSelectedChoices(loadedChoices.value, mcVal));\n}\n\nconst setResultingValueGuard = ref(false);\n\nfunction setResultingValue(newValue: any) {\n setResultingValueGuard.value = true;\n try {\n resultingValue.value = newValue;\n } finally {\n // The guard suppresses the watch that pushes the model's value back into `selected`. A write the control does\n // not take verbatim - a ValueChangedAction that writes another value back, a disabled field that drops it, a\n // handler that throws and unwinds it - never reaches that watch, so the chips would go on showing a selection\n // the control never took. Comparing what the control holds against what was written is what restores it, and\n // it needs a deep comparison: for multiple selection the value reads back as a different array holding the\n // same items. The comparison waits for the next tick: under v-model the parent passes the written value back as\n // modelValue only when it re-renders, and a read before that sees the previous value, reverts the selection and\n // emits it, which the parent passes back in turn - the two keep swapping values without end.\n nextTick(() => {\n const current = multipleCompliantValue(resultingValue.value, multiple.value);\n if (!isEqual(current, newValue)) {\n updateSelectedFromValue(current, selected, multiple.value, taggable.value, loadedChoices.value);\n }\n setResultingValueGuard.value = false;\n });\n }\n}\n\nfunction getFullWidth(item: HTMLElement | null) {\n if (!item) return 0;\n const rect = item.getBoundingClientRect();\n const style = window.getComputedStyle(item);\n\n return rect.width + parseFloat(style.marginLeft) + parseFloat(style.marginRight);\n}\n\nfunction checkMultiline() {\n if (multiple.value && allowNull.value && selected.value != null && selected.value.length > 0 && dfSelectRef.value) {\n const dfSelect = dfSelectRef.value.$el;\n const inputWidth = dfSelect.querySelector('.v-input__control')?.clientWidth;\n const container = dfSelect.querySelector('.v-field__input');\n const items = container.querySelectorAll('.v-autocomplete__selection, .v-combobox__selection');\n\n const style = window.getComputedStyle(container);\n let selectedWidth = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);\n\n items.forEach((item: HTMLElement) => {\n selectedWidth += getFullWidth(item);\n });\n\n const clearableWidth = getFullWidth(dfSelect.querySelector('.v-field .v-field__clearable'));\n const appendWidth = getFullWidth(dfSelect.querySelector('.v-field .v-field__append-inner'));\n const chipGap = 2;\n isMultiline.value = inputWidth - selectedWidth - items.length * chipGap - appendWidth < clearableWidth;\n } else {\n isMultiline.value = false;\n }\n}\n\nfunction onMouseDown(event: MouseEvent) {\n // če je klik na close ikoni ali njenem childu\n const target = event.target;\n if (target instanceof HTMLElement && target.closest('.v-chip__close')) {\n event.stopPropagation();\n event.preventDefault();\n }\n}\n\nwatch(\n selected,\n (newValue) => {\n if (vuetifyBindings.value.readonly || resolvingValue.value > 0) return;\n nextTick(() => {\n const mcVal = multipleCompliantValue(newValue, multiple.value);\n emitModelValueDisplay(mcVal);\n setResultingValue(mcVal);\n });\n },\n { deep: true },\n);\nwatch(\n resultingValue,\n (newValue: any) => {\n if (setResultingValueGuard.value) return;\n const mcVal = multipleCompliantValue(newValue, multiple.value);\n const resolved = resolveValueChoices(mcVal);\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n resolved?.then(() => {\n // A value set while this call was in flight started its own resolution and owns `selected` from then on.\n if (!isEqual(multipleCompliantValue(resultingValue.value, multiple.value), mcVal)) return;\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n });\n },\n { deep: true },\n);\n\nwatch(setResultingValueGuard, () => {\n if (!setResultingValueGuard.value) {\n checkMultiline();\n }\n});\n\nfunction resetQuery() {\n if (searchText.value != null && searchText.value.length > 0) {\n searchText.value = null;\n queryOptions();\n }\n}\n\nfunction onSelect(/* val: any */) {\n resetQuery();\n if (vuetifyBindings.value.readonly || taggable.value) return;\n const mcVal = multipleCompliantValue(selected.value, multiple.value);\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n setResultingValue(mcVal);\n}\n\nfunction chipClose(event: MouseEvent, itemValue: any) {\n event.stopPropagation();\n if (vuetifyBindings.value.readonly || taggable.value) {\n if (taggable.value) {\n selected.value = selected.value.filter((v: any) => v !== itemValue);\n }\n return;\n }\n let mcVal;\n if (multiple.value && Array.isArray(selected.value)) {\n mcVal = multipleCompliantValue(\n selected.value.filter((v) => v !== itemValue),\n multiple.value,\n );\n } else {\n mcVal = null;\n }\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n setResultingValue(mcVal);\n}\n\nasync function queryOptions(queryValue?: any, idValue?: any): Promise<void> {\n if (vuetifyBindings.value.readonly) return;\n searchText.value = queryValue;\n if (choices.value || propsWithDefaults.fetchChoices === undefined) return;\n const fetchCounter = ++fetchCounterGlobal.value;\n searching.value++;\n try {\n const newChoices = await propsWithDefaults.fetchChoices(queryValue, idValue);\n if (fetchCounter !== fetchCounterGlobal.value) return;\n // Taken after the fetch, from the value: choices resolveValueChoices() loaded while this call was in flight\n // must survive the search results replacing the rest.\n const selectedChoices = getSelectedChoices(\n loadedChoices.value,\n multipleCompliantValue(resultingValue.value, multiple.value),\n );\n loaded.value = unionBy([...selectedChoices, ...newChoices], 'id');\n takeLoaded.value = true;\n } finally {\n searching.value--;\n }\n}\n\n/**\n * Loads the choices for the ids in `mcVal` that loadedChoices has none for, through fetchChoices' idValue. Returns\n * null when there is nothing to load: no fetchChoices, a taggable select (its value is not limited to choices), or\n * every id already has its choice. An id fetchChoices returns no choice for stays without one, and the next\n * reconciliation against loadedChoices drops it from the value.\n */\nfunction resolveValueChoices(mcVal: any): Promise<void> | null {\n const fetchChoices = propsWithDefaults.fetchChoices;\n if (fetchChoices === undefined || taggable.value || mcVal == null) return null;\n const unresolved = castArray(mcVal).filter((val) => !loadedChoices.value.some((choice) => choice.id === val));\n if (!unresolved.length) return null;\n resolvingValue.value++;\n return (async () => {\n try {\n const newChoices = await fetchChoices(undefined, multiple.value ? unresolved : unresolved[0]);\n loaded.value = unionBy([...loadedChoices.value, ...newChoices], 'id');\n takeLoaded.value = true;\n } finally {\n resolvingValue.value--;\n }\n })();\n}\n\nfunction initialValueCheck() {\n let val = resultingValue.value;\n if (!allowNull.value && val == null && options.value.length) {\n // Starting settings: check if value is mandatory and select the first item from the options\n val = options.value[0].value;\n }\n val = multipleCompliantValue(val, multiple.value);\n updateSelectedFromValue(val, selected, multiple.value, taggable.value, loadedChoices.value);\n if (resolvingValue.value > 0) return;\n emitModelValueDisplay(val);\n setResultingValue(val);\n}\n\n// Starting settings: with fetchChoices, a value is first resolved into its choices and only then reconciled against\n// them. Anything else - an empty value, a taggable select - goes through queryOptions() with the value as idValue.\nlet initialLoad: Promise<void> | null = null;\nif (propsWithDefaults.fetchChoices !== undefined) {\n initialLoad =\n resolveValueChoices(multipleCompliantValue(resultingValue.value, multiple.value)) ??\n queryOptions(undefined, resultingValue.value);\n}\n\ninitialValueCheck();\n\ninitialLoad?.then(() => {\n initialValueCheck();\n});\n</script>\n\n<style scoped>\n.df-select-multirow :deep(.v-field__clearable) {\n position: absolute;\n}\n\n.df-select-multirow :deep(.v-field__append-inner) {\n margin-top: 24px;\n}\n\n.df-select-multirow :deep(.v-autocomplete .v-field:not(.v-field--focused) input) {\n min-width: 24px;\n}\n</style>\n","<template>\n <div v-if=\"isRendered\" class=\"df-textarea-container\" :class=\"[densityClass, visibilityClass]\">\n <v-textarea\n v-model=\"value\"\n :class=\"cssClass\"\n :rows=\"rows\"\n :auto-grow=\"(maxRows || 0) > 0\"\n :max-rows=\"maxRows\"\n v-bind=\"vuetifyBindings as any\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"showErrors\" /></template>\n </v-textarea>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { toRefs } from 'vue';\n\nimport { DfTextAreaProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfTextAreaProps>(), {\n ...defaultBaseProps,\n rows: undefined,\n maxRows: undefined,\n});\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, showErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\nconst { cssClass } = toRefs(props);\n</script>\n","<template>\n <div v-if=\"isRendered\" class=\"df-textarea-container\" :class=\"[densityClass, visibilityClass]\">\n <v-textarea\n v-model=\"value\"\n :class=\"cssClass\"\n :rows=\"rows\"\n :auto-grow=\"(maxRows || 0) > 0\"\n :max-rows=\"maxRows\"\n v-bind=\"vuetifyBindings as any\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"showErrors\" /></template>\n </v-textarea>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { toRefs } from 'vue';\n\nimport { DfTextAreaProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfTextAreaProps>(), {\n ...defaultBaseProps,\n rows: undefined,\n maxRows: undefined,\n});\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, showErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\nconst { cssClass } = toRefs(props);\n</script>\n","export { default as DfActions } from './df-actions.vue';\nexport { default as DfCheckbox } from './df-checkbox.vue';\nexport { default as DfColor } from './df-color.vue';\nexport { default as DfDateTime } from './df-datetime.vue';\nexport { default as DfFile } from './df-file.vue';\nexport { default as DfImage } from './df-image.vue';\nexport { default as DfInput } from './df-input.vue';\nexport { default as DfInputHint } from './helpers/df-input-hint.vue';\nexport { default as DfLabel } from './helpers/df-label.vue';\nexport { default as DfRtfEditor } from './df-rtf-editor.vue';\nexport { default as DfSelect } from './df-select.vue';\nexport { default as DfTextArea } from './df-text-area.vue';\n","export { VAutocomplete } from 'vuetify/components/VAutocomplete';\nexport { VBtn } from 'vuetify/components/VBtn';\nexport { VCheckbox } from 'vuetify/components/VCheckbox';\nexport { VChip } from 'vuetify/components/VChip';\nexport { VCombobox } from 'vuetify/components/VCombobox';\nexport { VColorPicker } from 'vuetify/components/VColorPicker';\nexport { VConfirmEdit } from 'vuetify/components/VConfirmEdit';\nexport { VDatePicker } from 'vuetify/components/VDatePicker';\nexport { VField } from 'vuetify/components/VField';\nexport { VFileInput } from 'vuetify/components/VFileInput';\nexport { VRow, VCol } from 'vuetify/components/VGrid';\nexport { VIcon } from 'vuetify/components/VIcon';\nexport { VImg } from 'vuetify/components/VImg';\nexport { VInput } from 'vuetify/components/VInput';\nexport { VListItem } from 'vuetify/components/VList';\nexport { VMenu } from 'vuetify/components/VMenu';\nexport { VNumberInput } from 'vuetify/components/VNumberInput';\nexport { VProgressLinear } from 'vuetify/components/VProgressLinear';\nexport { VSelect } from 'vuetify/components/VSelect';\nexport { VSwitch } from 'vuetify/components/VSwitch';\nexport { VTextarea } from 'vuetify/components/VTextarea';\nexport { VTextField } from 'vuetify/components/VTextField';\nexport { VTimePicker } from 'vuetify/components/VTimePicker';\n\n// run this in the src folder to get list of used components\n// grep -r -o \"<v-[a-zA-Z0-9-]*\" --include=\"*.vue\" . | sed 's/.*:<//' | sort | uniq\n","import {\n DfActions,\n DfCheckbox,\n DfColor,\n DfDateTime,\n DfFile,\n DfImage,\n DfInput,\n DfInputHint,\n DfLabel,\n DfRtfEditor,\n DfSelect,\n DfTextArea,\n} from './dynamicforms-components';\n\n/**\n * Every component this library draws with, keyed by the tag a layout names it by.\n *\n * A rendering layer that resolves a component by name out of a map - `@dynamicforms/vuetify-modal-form-kit`'s\n * `<component-render>` is one - is handed this instead of keeping a list of its own, which would have to be\n * extended whenever this package gains a component and would silently render nothing until it was.\n *\n * The keys are the kebab-case of the export names, so a tag names the same component whether it is looked up\n * here or left to Vue's own resolver after `DynamicFormsInputs` has registered the components globally.\n */\nexport const dfInputComponentsByTag = {\n 'df-actions': DfActions,\n 'df-checkbox': DfCheckbox,\n 'df-color': DfColor,\n 'df-date-time': DfDateTime,\n 'df-file': DfFile,\n 'df-image': DfImage,\n 'df-input': DfInput,\n 'df-input-hint': DfInputHint,\n 'df-label': DfLabel,\n 'df-rtf-editor': DfRtfEditor,\n 'df-select': DfSelect,\n 'df-text-area': DfTextArea,\n} as const;\n\n/** The tags {@link dfInputComponentsByTag} answers for. */\nexport type DfInputComponentTag = keyof typeof dfInputComponentsByTag;\n","import { Action, ClassTypes, MdString, ValidationError } from '@dynamicforms/vue-forms';\nimport { type Locale } from 'date-fns';\nimport { MaybeRef } from 'vue';\nimport { DefaultInputSlot } from 'vuetify/lib/components/VField/VField';\n\nimport {\n BaseProps,\n FileComms,\n Label,\n SelectChoice,\n SelectFetchChoices,\n VuetifyButtonSize,\n VuetifyDensity,\n} from './helpers';\n\ntype ShowAsGroup = 'no' | 'grouped' | 'grouped-no-borders';\n\nexport interface DfActionsProps {\n /** The actions to draw, this library's `Action` or a bare `@dynamicforms/vue-forms` one: what each button\n * renders as is read off the action's value, and a value stating nothing renders as the defaults. */\n actions: MaybeRef<Action[]>;\n buttonSize?: VuetifyButtonSize; // see https://vuetifyjs.com/en/api/v-btn/#props-size\n /** Forwarded to each button's `density` prop. See https://vuetifyjs.com/en/api/v-btn/#props-density */\n buttonDensity?: VuetifyDensity;\n showAsGroup?: ShowAsGroup;\n}\n\nexport interface DfCheckboxProps extends BaseProps {\n allowNull?: boolean;\n}\n\nexport interface DfColorProps extends BaseProps {\n allowNull?: boolean;\n}\n\nexport interface DfDateTimeProps extends BaseProps {\n inputType?: 'datetime' | 'date' | 'time';\n displayFormatDate?: string;\n displayFormatTime?: string;\n locale?: Locale;\n}\n\nexport interface DfFileProps extends BaseProps {\n comms: FileComms;\n /** Milliseconds between keep-alive touches. Overrides `defaultTouchInterval` from the plugin's\n * `VuetifyInputsSettings`, which in turn overrides the baked-in default of 60000. */\n touchInterval?: number;\n}\n\n/**\n * `comms.upload` must resolve to a value directly usable as an `<img>` src (typically the URL your backend\n * serves the image from): the component has no separate lookup for turning an identifier into a display URL,\n * so it renders `modelValue` itself as the preview once a file has been uploaded.\n */\nexport interface DfImageProps extends BaseProps {\n comms: FileComms;\n /** Milliseconds between keep-alive touches. Overrides `defaultTouchInterval` from the plugin's\n * `VuetifyInputsSettings`, which in turn overrides the baked-in default of 60000. */\n touchInterval?: number;\n}\n\nexport interface DfInputProps extends BaseProps {\n inputType?: 'text' | 'password' | 'email' | 'url' | 'number';\n precision?: number | null;\n step?: number;\n min?: number;\n max?: number;\n}\n\nexport interface DfInputHintProps {\n /** The errors to render. Rendered in place of {@link message} whenever there is one. */\n errors?: string | ValidationError[];\n /** The message to render, shown while there is no error. */\n message?: string | ValidationError[];\n /** Classes for the rendered errors. Defaults to `text-error`. */\n errorClasses?: ClassTypes;\n /** Classes for the rendered message. Defaults to no class. */\n messageClasses?: ClassTypes;\n}\n\nexport interface DfLabelProps {\n /** The slot data Vuetify hands a `#label` slot. Where it is given, its `label` is what is rendered. */\n data?: DefaultInputSlot & { label?: string | MdString };\n /** The label to render where no {@link data} is given: its text, and the icon it carries. */\n label: Label;\n /** Whether the label wraps over several lines. It is rendered on one line by default. */\n allowWrap?: boolean;\n}\n\nexport interface DfRtfEditorProps extends BaseProps {\n minHeight?: string;\n /** Size of the toolbar's buttons, forwarded to each one's `size` prop (`v-btn`'s, or `<df-actions>`'s\n * `buttonSize` for the grouped clusters). See https://vuetifyjs.com/en/api/v-btn/#props-size */\n toolbarButtonSize?: VuetifyButtonSize;\n /** `font-family` of the editing area and its named block styles (Title, Subtitle, Info box, Side quote, article\n * category). Defaults to `'inherit'`: the component loads no font of its own, so the editor renders in whatever\n * font the surrounding page already set. Pass any valid CSS `font-family` value to override it; loading the\n * font itself, if it isn't a system font, is the application's responsibility. */\n fontFamily?: string;\n}\n\nexport interface DfSelectProps extends BaseProps {\n choices?: SelectChoice[];\n multiple?: boolean;\n allowTags?: boolean;\n allowNull?: boolean;\n fetchChoices?: SelectFetchChoices;\n}\n\nexport interface DfTextAreaProps extends BaseProps {\n rows?: number;\n maxRows?: number;\n}\n","import { App } from 'vue';\n\nimport * as Inputs from './dynamicforms-components';\nimport { VuetifyInputsSettings, vuetifyInputsSettingsKey } from './helpers';\nimport * as VuetifyComponents from './vuetify-components';\n\nexport * from './helpers';\nexport * as VuetifyComponents from './vuetify-components';\nexport * from './dynamicforms-components';\nexport * from './dynamicforms-components-by-tag';\nexport * as DfInputComponents from './dynamicforms-components';\nexport * as DfInputComponentProps from './dynamicforms-component-props';\n\nexport interface DynamicFormsInputsOptions extends VuetifyInputsSettings {\n registerComponents: boolean;\n registerVuetifyComponents: boolean;\n}\n\nexport const DynamicFormsInputs = {\n install: (app: App, options?: Partial<DynamicFormsInputsOptions>) => {\n app.provide(vuetifyInputsSettingsKey, options ?? {});\n if (options?.registerComponents ?? false) {\n Object.entries(Inputs).map(([name, component]) => app.component(name, component));\n }\n if (options?.registerVuetifyComponents ?? false) {\n Object.entries(VuetifyComponents).map(([name, component]) => app.component(name, component));\n }\n },\n};\n"],"x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dynamicforms-vuetify-inputs.js","names":["$slots","$slots"],"sources":["../node_modules/date-fns/locale/sl/_lib/formatDistance.js","../node_modules/date-fns/locale/_lib/buildFormatLongFn.js","../node_modules/date-fns/locale/sl/_lib/formatLong.js","../node_modules/date-fns/locale/sl/_lib/formatRelative.js","../node_modules/date-fns/locale/_lib/buildLocalizeFn.js","../node_modules/date-fns/locale/sl/_lib/localize.js","../node_modules/date-fns/locale/_lib/buildMatchFn.js","../node_modules/date-fns/locale/_lib/buildMatchPatternFn.js","../node_modules/date-fns/locale/sl/_lib/match.js","../node_modules/date-fns/locale/sl.js","../src/helpers/date-time-locale.ts","../src/helpers/df-file.interface.ts","../src/helpers/render-content.ts","../src/helpers/error-text.ts","../src/helpers/settings.ts","../src/helpers/messages-widget.vue","../src/helpers/messages-widget.vue","../src/helpers/df-input-hint.vue","../src/helpers/df-input-hint.vue","../src/helpers/df-label.vue","../src/helpers/df-label.vue","../src/helpers/shown-errors.ts","../src/helpers/input-base.ts","../src/helpers/input-base.vue","../src/helpers/input-base.vue","../src/helpers/translations.ts","../src/helpers/action/action-display-style.ts","../src/helpers/action/responsive-render-options.ts","../src/helpers/action/action-render-options.ts","../src/helpers/action/action.ts","../src/helpers/use-file-touch-keepalive.ts","../src/df-actions.vue","../src/df-actions.vue","../src/df-checkbox.vue","../src/df-checkbox.vue","../src/helpers/client-rendered.ts","../src/helpers/confirm-actions.vue","../src/helpers/confirm-actions.vue","../src/helpers/picker-double-click.ts","../src/df-color.vue","../src/df-color.vue","../src/df-datetime.vue","../src/df-datetime.vue","../src/df-file.vue","../src/df-file.vue","../src/df-image.vue","../src/df-image.vue","../src/df-input.vue","../src/df-input.vue","../src/helpers/rtf-editor/block-styles.ts","../src/helpers/rtf-editor/image-paste.ts","../src/helpers/rtf-editor/link-with-download.ts","../src/helpers/rtf-editor/media-embed.ts","../src/helpers/rtf-editor/use-editor-tick.ts","../src/helpers/rtf-editor/rtf-toolbar.vue","../src/helpers/rtf-editor/rtf-toolbar.vue","../src/helpers/rtf-editor/word-paste.ts","../src/helpers/rtf-editor/editor-core.vue","../src/helpers/rtf-editor/editor-core.vue","../src/df-rtf-editor.vue","../src/df-rtf-editor.vue","../src/helpers/df-select.helper.ts","../src/df-select.vue","../src/df-select.vue","../src/df-text-area.vue","../src/df-text-area.vue","../src/dynamicforms-components.ts","../src/vuetify-components.ts","../src/dynamicforms-components-by-tag.ts","../src/dynamicforms-component-props.ts","../src/index.ts"],"sourcesContent":["function isPluralType(val) {\n return val.one !== undefined;\n}\n\nconst formatDistanceLocale = {\n lessThanXSeconds: {\n present: {\n one: \"manj kot {{count}} sekunda\",\n two: \"manj kot {{count}} sekundi\",\n few: \"manj kot {{count}} sekunde\",\n other: \"manj kot {{count}} sekund\",\n },\n past: {\n one: \"manj kot {{count}} sekundo\",\n two: \"manj kot {{count}} sekundama\",\n few: \"manj kot {{count}} sekundami\",\n other: \"manj kot {{count}} sekundami\",\n },\n future: {\n one: \"manj kot {{count}} sekundo\",\n two: \"manj kot {{count}} sekundi\",\n few: \"manj kot {{count}} sekunde\",\n other: \"manj kot {{count}} sekund\",\n },\n },\n\n xSeconds: {\n present: {\n one: \"{{count}} sekunda\",\n two: \"{{count}} sekundi\",\n few: \"{{count}} sekunde\",\n other: \"{{count}} sekund\",\n },\n past: {\n one: \"{{count}} sekundo\",\n two: \"{{count}} sekundama\",\n few: \"{{count}} sekundami\",\n other: \"{{count}} sekundami\",\n },\n future: {\n one: \"{{count}} sekundo\",\n two: \"{{count}} sekundi\",\n few: \"{{count}} sekunde\",\n other: \"{{count}} sekund\",\n },\n },\n\n halfAMinute: \"pol minute\",\n\n lessThanXMinutes: {\n present: {\n one: \"manj kot {{count}} minuta\",\n two: \"manj kot {{count}} minuti\",\n few: \"manj kot {{count}} minute\",\n other: \"manj kot {{count}} minut\",\n },\n past: {\n one: \"manj kot {{count}} minuto\",\n two: \"manj kot {{count}} minutama\",\n few: \"manj kot {{count}} minutami\",\n other: \"manj kot {{count}} minutami\",\n },\n future: {\n one: \"manj kot {{count}} minuto\",\n two: \"manj kot {{count}} minuti\",\n few: \"manj kot {{count}} minute\",\n other: \"manj kot {{count}} minut\",\n },\n },\n\n xMinutes: {\n present: {\n one: \"{{count}} minuta\",\n two: \"{{count}} minuti\",\n few: \"{{count}} minute\",\n other: \"{{count}} minut\",\n },\n past: {\n one: \"{{count}} minuto\",\n two: \"{{count}} minutama\",\n few: \"{{count}} minutami\",\n other: \"{{count}} minutami\",\n },\n future: {\n one: \"{{count}} minuto\",\n two: \"{{count}} minuti\",\n few: \"{{count}} minute\",\n other: \"{{count}} minut\",\n },\n },\n\n aboutXHours: {\n present: {\n one: \"približno {{count}} ura\",\n two: \"približno {{count}} uri\",\n few: \"približno {{count}} ure\",\n other: \"približno {{count}} ur\",\n },\n past: {\n one: \"približno {{count}} uro\",\n two: \"približno {{count}} urama\",\n few: \"približno {{count}} urami\",\n other: \"približno {{count}} urami\",\n },\n future: {\n one: \"približno {{count}} uro\",\n two: \"približno {{count}} uri\",\n few: \"približno {{count}} ure\",\n other: \"približno {{count}} ur\",\n },\n },\n\n xHours: {\n present: {\n one: \"{{count}} ura\",\n two: \"{{count}} uri\",\n few: \"{{count}} ure\",\n other: \"{{count}} ur\",\n },\n past: {\n one: \"{{count}} uro\",\n two: \"{{count}} urama\",\n few: \"{{count}} urami\",\n other: \"{{count}} urami\",\n },\n future: {\n one: \"{{count}} uro\",\n two: \"{{count}} uri\",\n few: \"{{count}} ure\",\n other: \"{{count}} ur\",\n },\n },\n\n xDays: {\n present: {\n one: \"{{count}} dan\",\n two: \"{{count}} dni\",\n few: \"{{count}} dni\",\n other: \"{{count}} dni\",\n },\n past: {\n one: \"{{count}} dnem\",\n two: \"{{count}} dnevoma\",\n few: \"{{count}} dnevi\",\n other: \"{{count}} dnevi\",\n },\n future: {\n one: \"{{count}} dan\",\n two: \"{{count}} dni\",\n few: \"{{count}} dni\",\n other: \"{{count}} dni\",\n },\n },\n\n // no tenses for weeks?\n aboutXWeeks: {\n one: \"približno {{count}} teden\",\n two: \"približno {{count}} tedna\",\n few: \"približno {{count}} tedne\",\n other: \"približno {{count}} tednov\",\n },\n\n // no tenses for weeks?\n xWeeks: {\n one: \"{{count}} teden\",\n two: \"{{count}} tedna\",\n few: \"{{count}} tedne\",\n other: \"{{count}} tednov\",\n },\n\n aboutXMonths: {\n present: {\n one: \"približno {{count}} mesec\",\n two: \"približno {{count}} meseca\",\n few: \"približno {{count}} mesece\",\n other: \"približno {{count}} mesecev\",\n },\n past: {\n one: \"približno {{count}} mesecem\",\n two: \"približno {{count}} mesecema\",\n few: \"približno {{count}} meseci\",\n other: \"približno {{count}} meseci\",\n },\n future: {\n one: \"približno {{count}} mesec\",\n two: \"približno {{count}} meseca\",\n few: \"približno {{count}} mesece\",\n other: \"približno {{count}} mesecev\",\n },\n },\n\n xMonths: {\n present: {\n one: \"{{count}} mesec\",\n two: \"{{count}} meseca\",\n few: \"{{count}} meseci\",\n other: \"{{count}} mesecev\",\n },\n past: {\n one: \"{{count}} mesecem\",\n two: \"{{count}} mesecema\",\n few: \"{{count}} meseci\",\n other: \"{{count}} meseci\",\n },\n future: {\n one: \"{{count}} mesec\",\n two: \"{{count}} meseca\",\n few: \"{{count}} mesece\",\n other: \"{{count}} mesecev\",\n },\n },\n\n aboutXYears: {\n present: {\n one: \"približno {{count}} leto\",\n two: \"približno {{count}} leti\",\n few: \"približno {{count}} leta\",\n other: \"približno {{count}} let\",\n },\n past: {\n one: \"približno {{count}} letom\",\n two: \"približno {{count}} letoma\",\n few: \"približno {{count}} leti\",\n other: \"približno {{count}} leti\",\n },\n future: {\n one: \"približno {{count}} leto\",\n two: \"približno {{count}} leti\",\n few: \"približno {{count}} leta\",\n other: \"približno {{count}} let\",\n },\n },\n\n xYears: {\n present: {\n one: \"{{count}} leto\",\n two: \"{{count}} leti\",\n few: \"{{count}} leta\",\n other: \"{{count}} let\",\n },\n past: {\n one: \"{{count}} letom\",\n two: \"{{count}} letoma\",\n few: \"{{count}} leti\",\n other: \"{{count}} leti\",\n },\n future: {\n one: \"{{count}} leto\",\n two: \"{{count}} leti\",\n few: \"{{count}} leta\",\n other: \"{{count}} let\",\n },\n },\n\n overXYears: {\n present: {\n one: \"več kot {{count}} leto\",\n two: \"več kot {{count}} leti\",\n few: \"več kot {{count}} leta\",\n other: \"več kot {{count}} let\",\n },\n past: {\n one: \"več kot {{count}} letom\",\n two: \"več kot {{count}} letoma\",\n few: \"več kot {{count}} leti\",\n other: \"več kot {{count}} leti\",\n },\n future: {\n one: \"več kot {{count}} leto\",\n two: \"več kot {{count}} leti\",\n few: \"več kot {{count}} leta\",\n other: \"več kot {{count}} let\",\n },\n },\n\n almostXYears: {\n present: {\n one: \"skoraj {{count}} leto\",\n two: \"skoraj {{count}} leti\",\n few: \"skoraj {{count}} leta\",\n other: \"skoraj {{count}} let\",\n },\n past: {\n one: \"skoraj {{count}} letom\",\n two: \"skoraj {{count}} letoma\",\n few: \"skoraj {{count}} leti\",\n other: \"skoraj {{count}} leti\",\n },\n future: {\n one: \"skoraj {{count}} leto\",\n two: \"skoraj {{count}} leti\",\n few: \"skoraj {{count}} leta\",\n other: \"skoraj {{count}} let\",\n },\n },\n};\n\nfunction getFormFromCount(count) {\n switch (count % 100) {\n case 1:\n return \"one\";\n case 2:\n return \"two\";\n case 3:\n case 4:\n return \"few\";\n default:\n return \"other\";\n }\n}\n\nexport const formatDistance = (token, count, options) => {\n let result = \"\";\n let tense = \"present\";\n\n if (options?.addSuffix) {\n if (options.comparison && options.comparison > 0) {\n tense = \"future\";\n result = \"čez \";\n } else {\n tense = \"past\";\n result = \"pred \";\n }\n }\n\n const tokenValue = formatDistanceLocale[token];\n\n if (typeof tokenValue === \"string\") {\n result += tokenValue;\n } else {\n const form = getFormFromCount(count);\n if (isPluralType(tokenValue)) {\n result += tokenValue[form].replace(\"{{count}}\", String(count));\n } else {\n result += tokenValue[tense][form].replace(\"{{count}}\", String(count));\n }\n }\n\n return result;\n};\n","export function buildFormatLongFn(args) {\n return (options = {}) => {\n // TODO: Remove String()\n const width = options.width ? String(options.width) : args.defaultWidth;\n const format = args.formats[width] || args.formats[args.defaultWidth];\n return format;\n };\n}\n","import { buildFormatLongFn } from \"../../_lib/buildFormatLongFn.js\";\n\nconst dateFormats = {\n full: \"EEEE, dd. MMMM y\",\n long: \"dd. MMMM y\",\n medium: \"d. MMM y\",\n short: \"d. MM. yy\",\n};\n\nconst timeFormats = {\n full: \"HH:mm:ss zzzz\",\n long: \"HH:mm:ss z\",\n medium: \"HH:mm:ss\",\n short: \"HH:mm\",\n};\n\nconst dateTimeFormats = {\n full: \"{{date}} {{time}}\",\n long: \"{{date}} {{time}}\",\n medium: \"{{date}} {{time}}\",\n short: \"{{date}} {{time}}\",\n};\n\nexport const formatLong = {\n date: buildFormatLongFn({\n formats: dateFormats,\n defaultWidth: \"full\",\n }),\n\n time: buildFormatLongFn({\n formats: timeFormats,\n defaultWidth: \"full\",\n }),\n\n dateTime: buildFormatLongFn({\n formats: dateTimeFormats,\n defaultWidth: \"full\",\n }),\n};\n","const formatRelativeLocale = {\n lastWeek: (date) => {\n const day = date.getDay();\n\n switch (day) {\n case 0:\n return \"'prejšnjo nedeljo ob' p\";\n case 3:\n return \"'prejšnjo sredo ob' p\";\n case 6:\n return \"'prejšnjo soboto ob' p\";\n default:\n return \"'prejšnji' EEEE 'ob' p\";\n }\n },\n yesterday: \"'včeraj ob' p\",\n today: \"'danes ob' p\",\n tomorrow: \"'jutri ob' p\",\n nextWeek: (date) => {\n const day = date.getDay();\n\n switch (day) {\n case 0:\n return \"'naslednjo nedeljo ob' p\";\n case 3:\n return \"'naslednjo sredo ob' p\";\n case 6:\n return \"'naslednjo soboto ob' p\";\n default:\n return \"'naslednji' EEEE 'ob' p\";\n }\n },\n other: \"P\",\n};\n\nexport const formatRelative = (token, date, _baseDate, _options) => {\n const format = formatRelativeLocale[token];\n\n if (typeof format === \"function\") {\n return format(date);\n }\n\n return format;\n};\n","/**\n * The localize function argument callback which allows to convert raw value to\n * the actual type.\n *\n * @param value - The value to convert\n *\n * @returns The converted value\n */\n\n/**\n * The map of localized values for each width.\n */\n\n/**\n * The index type of the locale unit value. It types conversion of units of\n * values that don't start at 0 (i.e. quarters).\n */\n\n/**\n * Converts the unit value to the tuple of values.\n */\n\n/**\n * The tuple of localized era values. The first element represents BC,\n * the second element represents AD.\n */\n\n/**\n * The tuple of localized quarter values. The first element represents Q1.\n */\n\n/**\n * The tuple of localized day values. The first element represents Sunday.\n */\n\n/**\n * The tuple of localized month values. The first element represents January.\n */\n\nexport function buildLocalizeFn(args) {\n return (value, options) => {\n const context = options?.context ? String(options.context) : \"standalone\";\n\n let valuesArray;\n if (context === \"formatting\" && args.formattingValues) {\n const defaultWidth = args.defaultFormattingWidth || args.defaultWidth;\n const width = options?.width ? String(options.width) : defaultWidth;\n\n valuesArray =\n args.formattingValues[width] || args.formattingValues[defaultWidth];\n } else {\n const defaultWidth = args.defaultWidth;\n const width = options?.width ? String(options.width) : args.defaultWidth;\n\n valuesArray = args.values[width] || args.values[defaultWidth];\n }\n const index = args.argumentCallback ? args.argumentCallback(value) : value;\n\n // @ts-expect-error - For some reason TypeScript just don't want to match it, no matter how hard we try. I challenge you to try to remove it!\n return valuesArray[index];\n };\n}\n","import { buildLocalizeFn } from \"../../_lib/buildLocalizeFn.js\";\n\nconst eraValues = {\n narrow: [\"pr. n. št.\", \"po n. št.\"],\n abbreviated: [\"pr. n. št.\", \"po n. št.\"],\n wide: [\"pred našim štetjem\", \"po našem štetju\"],\n};\n\nconst quarterValues = {\n narrow: [\"1\", \"2\", \"3\", \"4\"],\n abbreviated: [\"1. čet.\", \"2. čet.\", \"3. čet.\", \"4. čet.\"],\n wide: [\"1. četrtletje\", \"2. četrtletje\", \"3. četrtletje\", \"4. četrtletje\"],\n};\n\nconst monthValues = {\n narrow: [\"j\", \"f\", \"m\", \"a\", \"m\", \"j\", \"j\", \"a\", \"s\", \"o\", \"n\", \"d\"],\n abbreviated: [\n \"jan.\",\n \"feb.\",\n \"mar.\",\n \"apr.\",\n \"maj\",\n \"jun.\",\n \"jul.\",\n \"avg.\",\n \"sep.\",\n \"okt.\",\n \"nov.\",\n \"dec.\",\n ],\n\n wide: [\n \"januar\",\n \"februar\",\n \"marec\",\n \"april\",\n \"maj\",\n \"junij\",\n \"julij\",\n \"avgust\",\n \"september\",\n \"oktober\",\n \"november\",\n \"december\",\n ],\n};\n\nconst dayValues = {\n narrow: [\"n\", \"p\", \"t\", \"s\", \"č\", \"p\", \"s\"],\n short: [\"ned.\", \"pon.\", \"tor.\", \"sre.\", \"čet.\", \"pet.\", \"sob.\"],\n abbreviated: [\"ned.\", \"pon.\", \"tor.\", \"sre.\", \"čet.\", \"pet.\", \"sob.\"],\n\n wide: [\n \"nedelja\",\n \"ponedeljek\",\n \"torek\",\n \"sreda\",\n \"četrtek\",\n \"petek\",\n \"sobota\",\n ],\n};\n\nconst dayPeriodValues = {\n narrow: {\n am: \"d\",\n pm: \"p\",\n midnight: \"24.00\",\n noon: \"12.00\",\n morning: \"j\",\n afternoon: \"p\",\n evening: \"v\",\n night: \"n\",\n },\n abbreviated: {\n am: \"dop.\",\n pm: \"pop.\",\n midnight: \"poln.\",\n noon: \"pold.\",\n morning: \"jut.\",\n afternoon: \"pop.\",\n evening: \"več.\",\n night: \"noč\",\n },\n wide: {\n am: \"dop.\",\n pm: \"pop.\",\n midnight: \"polnoč\",\n noon: \"poldne\",\n morning: \"jutro\",\n afternoon: \"popoldne\",\n evening: \"večer\",\n night: \"noč\",\n },\n};\n\nconst formattingDayPeriodValues = {\n narrow: {\n am: \"d\",\n pm: \"p\",\n midnight: \"24.00\",\n noon: \"12.00\",\n morning: \"zj\",\n afternoon: \"p\",\n evening: \"zv\",\n night: \"po\",\n },\n abbreviated: {\n am: \"dop.\",\n pm: \"pop.\",\n midnight: \"opoln.\",\n noon: \"opold.\",\n morning: \"zjut.\",\n afternoon: \"pop.\",\n evening: \"zveč.\",\n night: \"ponoči\",\n },\n wide: {\n am: \"dop.\",\n pm: \"pop.\",\n midnight: \"opolnoči\",\n noon: \"opoldne\",\n morning: \"zjutraj\",\n afternoon: \"popoldan\",\n evening: \"zvečer\",\n night: \"ponoči\",\n },\n};\n\nconst ordinalNumber = (dirtyNumber, _options) => {\n const number = Number(dirtyNumber);\n return number + \".\";\n};\n\nexport const localize = {\n ordinalNumber,\n\n era: buildLocalizeFn({\n values: eraValues,\n defaultWidth: \"wide\",\n }),\n\n quarter: buildLocalizeFn({\n values: quarterValues,\n defaultWidth: \"wide\",\n argumentCallback: (quarter) => quarter - 1,\n }),\n\n month: buildLocalizeFn({\n values: monthValues,\n defaultWidth: \"wide\",\n }),\n\n day: buildLocalizeFn({\n values: dayValues,\n defaultWidth: \"wide\",\n }),\n\n dayPeriod: buildLocalizeFn({\n values: dayPeriodValues,\n defaultWidth: \"wide\",\n formattingValues: formattingDayPeriodValues,\n defaultFormattingWidth: \"wide\",\n }),\n};\n","export function buildMatchFn(args) {\n return (string, options = {}) => {\n const width = options.width;\n\n const matchPattern =\n (width && args.matchPatterns[width]) ||\n args.matchPatterns[args.defaultMatchWidth];\n const matchResult = string.match(matchPattern);\n\n if (!matchResult) {\n return null;\n }\n const matchedString = matchResult[0];\n\n const parsePatterns =\n (width && args.parsePatterns[width]) ||\n args.parsePatterns[args.defaultParseWidth];\n\n const key = Array.isArray(parsePatterns)\n ? findIndex(parsePatterns, (pattern) => pattern.test(matchedString))\n : // [TODO] -- I challenge you to fix the type\n findKey(parsePatterns, (pattern) => pattern.test(matchedString));\n\n let value;\n\n value = args.valueCallback ? args.valueCallback(key) : key;\n value = options.valueCallback\n ? // [TODO] -- I challenge you to fix the type\n options.valueCallback(value)\n : value;\n\n const rest = string.slice(matchedString.length);\n\n return { value, rest };\n };\n}\n\nfunction findKey(object, predicate) {\n for (const key in object) {\n if (\n Object.prototype.hasOwnProperty.call(object, key) &&\n predicate(object[key])\n ) {\n return key;\n }\n }\n return undefined;\n}\n\nfunction findIndex(array, predicate) {\n for (let key = 0; key < array.length; key++) {\n if (predicate(array[key])) {\n return key;\n }\n }\n return undefined;\n}\n","export function buildMatchPatternFn(args) {\n return (string, options = {}) => {\n const matchResult = string.match(args.matchPattern);\n if (!matchResult) return null;\n const matchedString = matchResult[0];\n\n const parseResult = string.match(args.parsePattern);\n if (!parseResult) return null;\n let value = args.valueCallback\n ? args.valueCallback(parseResult[0])\n : parseResult[0];\n\n // [TODO] I challenge you to fix the type\n value = options.valueCallback ? options.valueCallback(value) : value;\n\n const rest = string.slice(matchedString.length);\n\n return { value, rest };\n };\n}\n","import { buildMatchFn } from \"../../_lib/buildMatchFn.js\";\nimport { buildMatchPatternFn } from \"../../_lib/buildMatchPatternFn.js\";\n\nconst matchOrdinalNumberPattern = /^(\\d+)\\./i;\nconst parseOrdinalNumberPattern = /\\d+/i;\n\nconst matchEraPatterns = {\n abbreviated: /^(pr\\. n\\. št\\.|po n\\. št\\.)/i,\n wide: /^(pred Kristusom|pred na[sš]im [sš]tetjem|po Kristusu|po na[sš]em [sš]tetju|na[sš]ega [sš]tetja)/i,\n};\nconst parseEraPatterns = {\n any: [/^pr/i, /^(po|na[sš]em)/i],\n};\n\nconst matchQuarterPatterns = {\n narrow: /^[1234]/i,\n abbreviated: /^[1234]\\.\\s?[čc]et\\.?/i,\n wide: /^[1234]\\. [čc]etrtletje/i,\n};\nconst parseQuarterPatterns = {\n any: [/1/i, /2/i, /3/i, /4/i],\n};\n\nconst matchMonthPatterns = {\n narrow: /^[jfmasond]/i,\n abbreviated:\n /^(jan\\.|feb\\.|mar\\.|apr\\.|maj|jun\\.|jul\\.|avg\\.|sep\\.|okt\\.|nov\\.|dec\\.)/i,\n wide: /^(januar|februar|marec|april|maj|junij|julij|avgust|september|oktober|november|december)/i,\n};\nconst parseMonthPatterns = {\n narrow: [\n /^j/i,\n /^f/i,\n /^m/i,\n /^a/i,\n /^m/i,\n /^j/i,\n /^j/i,\n /^a/i,\n /^s/i,\n /^o/i,\n /^n/i,\n /^d/i,\n ],\n\n abbreviated: [\n /^ja/i,\n /^fe/i,\n /^mar/i,\n /^ap/i,\n /^maj/i,\n /^jun/i,\n /^jul/i,\n /^av/i,\n /^s/i,\n /^o/i,\n /^n/i,\n /^d/i,\n ],\n\n wide: [\n /^ja/i,\n /^fe/i,\n /^mar/i,\n /^ap/i,\n /^maj/i,\n /^jun/i,\n /^jul/i,\n /^av/i,\n /^s/i,\n /^o/i,\n /^n/i,\n /^d/i,\n ],\n};\n\nconst matchDayPatterns = {\n narrow: /^[nptsčc]/i,\n short: /^(ned\\.|pon\\.|tor\\.|sre\\.|[cč]et\\.|pet\\.|sob\\.)/i,\n abbreviated: /^(ned\\.|pon\\.|tor\\.|sre\\.|[cč]et\\.|pet\\.|sob\\.)/i,\n wide: /^(nedelja|ponedeljek|torek|sreda|[cč]etrtek|petek|sobota)/i,\n};\nconst parseDayPatterns = {\n narrow: [/^n/i, /^p/i, /^t/i, /^s/i, /^[cč]/i, /^p/i, /^s/i],\n any: [/^n/i, /^po/i, /^t/i, /^sr/i, /^[cč]/i, /^pe/i, /^so/i],\n};\n\nconst matchDayPeriodPatterns = {\n narrow: /^(d|po?|z?v|n|z?j|24\\.00|12\\.00)/i,\n any: /^(dop\\.|pop\\.|o?poln(\\.|o[cč]i?)|o?pold(\\.|ne)|z?ve[cč](\\.|er)|(po)?no[cč]i?|popold(ne|an)|jut(\\.|ro)|zjut(\\.|raj))/i,\n};\nconst parseDayPeriodPatterns = {\n narrow: {\n am: /^d/i,\n pm: /^p/i,\n midnight: /^24/i,\n noon: /^12/i,\n morning: /^(z?j)/i,\n afternoon: /^p/i,\n evening: /^(z?v)/i,\n night: /^(n|po)/i,\n },\n any: {\n am: /^dop\\./i,\n pm: /^pop\\./i,\n midnight: /^o?poln/i,\n noon: /^o?pold/i,\n morning: /j/i,\n afternoon: /^pop\\./i,\n evening: /^z?ve/i,\n night: /(po)?no/i,\n },\n};\n\nexport const match = {\n ordinalNumber: buildMatchPatternFn({\n matchPattern: matchOrdinalNumberPattern,\n parsePattern: parseOrdinalNumberPattern,\n valueCallback: (value) => parseInt(value, 10),\n }),\n\n era: buildMatchFn({\n matchPatterns: matchEraPatterns,\n defaultMatchWidth: \"wide\",\n parsePatterns: parseEraPatterns,\n defaultParseWidth: \"any\",\n }),\n\n quarter: buildMatchFn({\n matchPatterns: matchQuarterPatterns,\n defaultMatchWidth: \"wide\",\n parsePatterns: parseQuarterPatterns,\n defaultParseWidth: \"any\",\n valueCallback: (index) => index + 1,\n }),\n\n month: buildMatchFn({\n matchPatterns: matchMonthPatterns,\n defaultMatchWidth: \"wide\",\n parsePatterns: parseMonthPatterns,\n defaultParseWidth: \"wide\",\n }),\n\n day: buildMatchFn({\n matchPatterns: matchDayPatterns,\n defaultMatchWidth: \"wide\",\n parsePatterns: parseDayPatterns,\n defaultParseWidth: \"any\",\n }),\n\n dayPeriod: buildMatchFn({\n matchPatterns: matchDayPeriodPatterns,\n defaultMatchWidth: \"any\",\n parsePatterns: parseDayPeriodPatterns,\n defaultParseWidth: \"any\",\n }),\n};\n","import { formatDistance } from \"./sl/_lib/formatDistance.js\";\nimport { formatLong } from \"./sl/_lib/formatLong.js\";\nimport { formatRelative } from \"./sl/_lib/formatRelative.js\";\nimport { localize } from \"./sl/_lib/localize.js\";\nimport { match } from \"./sl/_lib/match.js\";\n\n/**\n * @category Locales\n * @summary Slovenian locale.\n * @language Slovenian\n * @iso-639-2 slv\n * @author Adam Stradovnik [@Neoglyph](https://github.com/Neoglyph)\n * @author Mato Žgajner [@mzgajner](https://github.com/mzgajner)\n */\nexport const sl = {\n code: \"sl\",\n formatDistance: formatDistance,\n formatLong: formatLong,\n formatRelative: formatRelative,\n localize: localize,\n match: match,\n options: {\n weekStartsOn: 1 /* Monday */,\n firstWeekContainsDate: 1,\n },\n};\n\n// Fallback for modularized imports:\nexport default sl;\n","import { Locale } from 'date-fns';\nimport { sl } from 'date-fns/locale/sl';\nimport { isRef, ref, Ref } from 'vue';\n\nexport const DateTimeLocaleConfig = {\n dateTimeLocale: ref(sl),\n setDateTimeLocale(locale: Locale | Ref<Locale>) {\n if (isRef(locale)) {\n this.dateTimeLocale = locale;\n } else {\n this.dateTimeLocale.value = locale;\n }\n },\n};\n","export type FileProgressCallback = (loaded: number, total: number) => void;\n\n/**\n * Thrown by `FileComms.touch` or `FileComms.delete` when the backend confirms the file identifier no longer\n * exists there (e.g. its keep-alive TTL expired). The component reacts to this specific type by clearing the\n * field and, where a `control` is bound, showing `errorText` as a validation error. Any other thrown error is\n * treated as transient and left entirely to the consumer.\n */\nexport class FileGoneError extends Error {\n constructor(public errorText: string) {\n super(errorText);\n }\n}\n\nexport interface FileComms {\n /**\n * upload is called when a file is added to the input and needs to be uploaded to the backend for storage\n * the component will then set its modelValue to the file identifier returned by this function. when the form\n * is posted, only the identifier will be sent to the backend\n *\n * the method may throw an exception which will mean upload failure\n *\n * @param file the file to be uploaded\n * @param progressCallback callback function to call with current upload progress data.\n * See e.g. axios onUploadProgress for axios post method\n * @return file id\n */\n upload: (file: File, progressCallback?: FileProgressCallback) => Promise<string>;\n\n /**\n * delete is called when the file is removed from the input and needs to be deleted at the backend\n *\n * throw {@link FileGoneError} if the backend reports the file identifier is already gone; any other thrown\n * error is treated as a transient failure\n *\n * @param fileIdentifier the identifier that was returned by upload\n */\n delete: (fileIdentifier: string) => Promise<void>;\n\n /**\n * touch is called at a regular interval (see the `touchInterval` prop / `defaultTouchInterval` setting) to let\n * the backend know that the file is still in play and must not be discarded\n *\n * throw {@link FileGoneError} if the backend reports the file identifier no longer exists; any other thrown\n * error is treated as a transient failure and left to the consumer to act on, if at all\n *\n * @param fileIdentifier the identifier that was returned by upload\n */\n touch: (fileIdentifier: string) => Promise<void>;\n\n /**\n * getDownloadUrl is called when the user asks to download the file currently held by the field. Omit it if\n * the backend offers no way to retrieve an already-uploaded file: the component shows no download control\n * in that case.\n *\n * @param fileIdentifier the identifier that was returned by upload\n * @return a URL the browser can fetch the file from directly (e.g. a signed URL or a same-origin path)\n */\n getDownloadUrl?: (fileIdentifier: string) => string | Promise<string>;\n}\n","import { computed, ComputedRef, Ref, unref } from 'vue';\n\n/** A string rendered as markdown by `vue-markdown-render`, with its `options` and `plugins`. */\nexport class MdString extends String {\n plugins?: any[];\n options?: any;\n\n constructor(value: string, options?: any, plugins?: any[]) {\n super(value);\n this.plugins = plugins;\n this.options = options;\n }\n}\n\n/**\n * A string rendered as HTML: it is set as the `innerHTML` of a `div`. It is not sanitized, so a string holding text\n * from a user or a server is escaped or sanitized before it is wrapped.\n */\nexport class HtmlString extends String {}\n\n/**\n * A component to render content with: an HTML element or a registered component by its name, with its props and its\n * children. It has no HTML content of its own; HTML is an `HtmlString`.\n */\nexport interface SimpleComponentDef {\n componentName: string;\n /** The props of the component. A listener is a prop named `on` and the event, e.g. `onClick`. `innerHTML` is not\n * one: the component drops it. */\n componentProps?: Record<string, unknown> & { innerHTML?: never };\n /** The children of an HTML element, or the default slot of a component. A string renders as text. */\n children?: RenderContentNonCallable | readonly RenderContentNonCallable[];\n}\n\nexport type ClassType = string | string[] | Record<string, boolean>;\nexport type ClassTypes = ClassType | ClassType[];\n\nexport type RenderContentNonCallable = string | MdString | HtmlString | SimpleComponentDef;\nexport type RenderContentCallable = () => RenderContentNonCallable;\n/** Content in one of four forms - plain text, markdown, HTML or a component - or a function answering one. */\nexport type RenderContent = RenderContentNonCallable | RenderContentCallable;\n/** `RenderContent`, or a reference to it. */\nexport type RenderContentRef = RenderContent | Ref<RenderContent>;\n\n/** True where `content` names a component to render it with. */\nexport function isSimpleComponentDef(content?: RenderContentRef): content is SimpleComponentDef {\n const value = unref(content);\n // typeof null is 'object', and `in` throws on null\n return typeof value === 'object' && value !== null && 'componentName' in value;\n}\n\n/** True where `value` is content in one of the four forms: a string, an `MdString`, an `HtmlString` or a component. */\nexport function isRenderContent(value: unknown): value is RenderContentNonCallable {\n return typeof value === 'string' || value instanceof String || isSimpleComponentDef(value as RenderContentRef);\n}\n\n// a tag that starts or ends a block, or breaks a line: its text and the next one's are separate words\nconst blockTags = [\n 'address',\n 'article',\n 'aside',\n 'blockquote',\n 'br',\n 'dd',\n 'div',\n 'dl',\n 'dt',\n 'figcaption',\n 'figure',\n 'footer',\n 'h[1-6]',\n 'header',\n 'hr',\n 'li',\n 'main',\n 'nav',\n 'ol',\n 'p',\n 'pre',\n 'section',\n 'table',\n 'td',\n 'th',\n 'tr',\n 'ul',\n];\nconst blockBoundary = new RegExp(`</?(?:${blockTags.join('|')})\\\\b[^>]*>`, 'gi');\n\n// an ` ` until the text is complete: whitespace is collapsed and trimmed around it, never out of it\nconst nbspMark = '\\uE000';\n\n// read last for '&', so '&lt;' reads as '<'\nconst htmlEntities: Record<string, string> = {\n '<': '<',\n '>': '>',\n '"': '\"',\n ''': \"'\",\n ' ': nbspMark,\n '&': '&',\n};\n\n// the text of content, an HtmlString's whitespace collapsed but not trimmed, so that it keeps the space that separates\n// it from the content next to it, and its ` ` as nbspMark\nfunction contentText(content: RenderContentNonCallable): string {\n if (content instanceof HtmlString) {\n const text = content\n .toString()\n .replace(blockBoundary, ' ')\n .replace(/<[^>]*>/g, '')\n .replace(/\\s+/g, ' ');\n return Object.entries(htmlEntities).reduce((result, [entity, char]) => result.replaceAll(entity, char), text);\n }\n if (isSimpleComponentDef(content)) return childrenOf(content).map(contentText).join('');\n return content.toString();\n}\n\n/**\n * The text of `content` where only text is taken, such as an `aria-label`: a string and an `MdString` as written, an\n * `HtmlString` without its tags, its blocks separated by a space, whitespace collapsed and trimmed, and with `&`,\n * `<`, `>`, `"`, `'` and ` ` read, and a component as the text of its children joined, whitespace\n * collapsed and trimmed. An ` ` reads as a space that is neither collapsed nor trimmed.\n */\nexport function renderContentText(content: RenderContentNonCallable): string {\n if (!(content instanceof HtmlString) && !isSimpleComponentDef(content)) return content.toString();\n return contentText(content).replace(/\\s+/g, ' ').trim().replaceAll(nbspMark, ' ');\n}\n\n// the children of a component as an array, empty where it has none\nfunction childrenOf(content: SimpleComponentDef): readonly RenderContentNonCallable[] {\n const { children } = content;\n if (children === undefined) return [];\n return Array.isArray(children) ? children : [children as RenderContentNonCallable];\n}\n\n/** True where `content` is a function answering the content. */\nexport function isCallableFunction(content?: RenderContentRef): content is RenderContentCallable {\n return typeof unref(content) === 'function';\n}\n\n/** Which of the four forms content takes. */\nexport type RenderContentKind = 'string' | 'md' | 'html' | 'component';\n\n/**\n * Content with the CSS classes it is rendered with, described as what renders it: `componentName`, its\n * `componentBindings`, its `componentChildren`, its `componentBody` and its `extraClasses`. `componentName` is\n * `'template'` for plain text, `'vue-markdown'` for markdown, `'html'` for an `HtmlString` and the component's name\n * for a `SimpleComponentDef`; `componentBody` is the text of plain text and the HTML of an `HtmlString`.\n *\n * `MessagesWidget` renders it, and so does any component that reads those five members. A reference or a function as\n * the content is read on every render, so what it answers reaches the screen without the value being built again.\n */\nexport class RenderableValue {\n // an ordinary property rather than a #private one: a value held in reactive state is read through its proxy, and a\n // #private member read through a proxy throws. The proxy also unwraps the ref, hence unref on read\n private readonly kindRef: ComputedRef<RenderContentKind>;\n\n constructor(\n private readonly content: RenderContentRef = '',\n public classes: ClassTypes = '',\n ) {\n this.kindRef = computed(() => {\n const resolved = this.resolvedText;\n if (resolved instanceof MdString) return 'md';\n if (resolved instanceof HtmlString) return 'html';\n if (isSimpleComponentDef(resolved)) return 'component';\n return 'string';\n });\n }\n\n /** The content as it reads now: a reference unwrapped and a function called. */\n get resolvedText(): RenderContentNonCallable {\n const content = unref(this.content);\n return isCallableFunction(content) ? content() : content;\n }\n\n /** Which of the four forms the content takes now. */\n get kind(): RenderContentKind {\n return unref(this.kindRef);\n }\n\n get componentName(): string {\n switch (this.kind) {\n case 'md':\n return 'vue-markdown';\n case 'html':\n return 'html';\n case 'component':\n return (this.resolvedText as SimpleComponentDef).componentName;\n default:\n return 'template';\n }\n }\n\n get componentBindings(): Record<string, any> {\n switch (this.kind) {\n case 'md': {\n const text = this.resolvedText as MdString;\n return { source: text.toString(), options: text.options, plugins: text.plugins };\n }\n case 'component': {\n // the props never set inner HTML: HTML content is an HtmlString\n const props: Record<string, unknown> = { ...(this.resolvedText as SimpleComponentDef).componentProps };\n delete props.innerHTML;\n return props;\n }\n default:\n return {};\n }\n }\n\n /** The children of a component; empty for the other forms. */\n get componentChildren(): readonly RenderContentNonCallable[] {\n return this.kind === 'component' ? childrenOf(this.resolvedText as SimpleComponentDef) : [];\n }\n\n get componentBody(): string {\n switch (this.kind) {\n case 'md':\n case 'component':\n return '';\n default:\n return this.resolvedText.toString();\n }\n }\n\n get extraClasses(): ClassTypes {\n return this.classes;\n }\n}\n","import type { ErrorDescription } from '@dynamicforms/vue-forms';\n\nimport { isRenderContent, type RenderContentNonCallable, renderContentText } from './render-content';\nimport type { VuetifyInputsSettings } from './settings';\n\n/**\n * An error as a component accepts it for rendering: content in one of the four forms (a string, an `MdString`, an\n * `HtmlString` or a `SimpleComponentDef`), which renders as it is, or an error description of which any member may\n * be missing.\n */\nexport type ErrorInput = RenderContentNonCallable | Partial<ErrorDescription>;\n\n/**\n * `error` with every missing member set: `code` to `''`, `params` to `{}`, `detail` to `''` and `origin` to\n * `'application'`. Content becomes an error without a code, its text (`renderContentText`) as the `detail`.\n */\nexport function toErrorDescription(error: ErrorInput): ErrorDescription {\n if (isRenderContent(error)) return { code: '', params: {}, detail: renderContentText(error), origin: 'application' };\n return {\n code: typeof error.code === 'string' ? error.code : '',\n params: error.params ?? {},\n detail: typeof error.detail === 'string' ? error.detail : '',\n origin: typeof error.origin === 'string' && error.origin ? error.origin : 'application',\n };\n}\n\n/**\n * What a component renders for `error`. Content renders as it is. An error without a code renders as its\n * `detail`: it is text in the user's language. An error with a code renders as the `errorText` setting's answer, and\n * as its `detail` where the setting is not given or answers `undefined`.\n */\nexport function errorText(error: ErrorInput, settings: VuetifyInputsSettings): RenderContentNonCallable {\n if (isRenderContent(error)) return error;\n const description = toErrorDescription(error);\n if (!description.code) return description.detail;\n return settings.errorText?.(description) ?? description.detail;\n}\n","import type { TranslateFunction } from '@dynamicforms/translatable';\nimport type { ErrorDescription, FieldBase, ValidationError } from '@dynamicforms/vue-forms';\nimport type { Locale } from 'date-fns';\nimport type { MaybeRef } from 'vue';\n\nimport { FieldDensity, type FieldVariant } from '@/helpers/input-base';\nimport type { RenderContentNonCallable } from '@/helpers/render-content';\n\n/**\n * Converts an error to the content it renders as: plain text, an `MdString` for markdown, an `HtmlString` for HTML\n * or a `SimpleComponentDef` for a component. `undefined` renders the error's `detail`. It is called for an error with\n * a code. It runs while the errors are rendered, so the reactive state it reads, such as the locale, is tracked.\n */\nexport type ErrorText = (error: ErrorDescription) => RenderContentNonCallable | undefined;\n\nexport interface VuetifyInputsSettings {\n defaultVariant?: FieldVariant;\n defaultDensity?: FieldDensity;\n /** Milliseconds between `<df-file>`/`<df-image>` keep-alive touches; overridable per field by their\n * `touchInterval` prop. Defaults to 60000 when neither is set. */\n defaultTouchInterval?: number;\n /**\n * The condition that decides whether an error is shown, asked for each error a component would show, with the\n * answer the default rule gives (see `useShownErrors`); its answer stands. `control` is the element the component\n * is bound to, absent where the errors come from the `errors` prop. It runs while the errors are rendered, so it\n * is synchronous and changes nothing.\n */\n shownErrors?: (error: ValidationError, control: FieldBase | undefined, shownByDefault: boolean) => boolean;\n /**\n * The content an error renders as; see `ErrorText`. Without it, an error renders as its `detail`.\n */\n errorText?: ErrorText;\n /**\n * The translation function of the library's strings, shaped like vue-i18n's `t`. Where it is given, `translate()`\n * called while a component that reads these settings sets up or renders uses it in place of the one\n * `translateStrings` set for the process. Under server-side rendering, an app per request gives each request its\n * own.\n */\n translate?: TranslateFunction;\n /** The namespace `translate` looks the library's keys up under: `${translateNamespace}.${key}`. */\n translateNamespace?: string;\n /**\n * The date-fns locale `<df-date-time>` formats and parses with in this app, in place of\n * `DateTimeLocaleConfig.dateTimeLocale`. A component's `locale` prop takes precedence.\n */\n dateTimeLocale?: MaybeRef<Locale>;\n}\n\nexport const vuetifyInputsSettingsKey = Symbol('vuetifyInputsSettingsKey');\n","<template>\n <render />\n</template>\n\n<script setup lang=\"ts\">\nimport { h, inject, resolveComponent, type VNodeChild } from 'vue';\nimport VueMarkdown from 'vue-markdown-render';\n\nimport type { MessagesWidgetProps } from '../dynamicforms-component-props';\n\nimport { type ErrorInput, errorText } from './error-text';\nimport { RenderableValue, type RenderContentNonCallable } from './render-content';\nimport { type VuetifyInputsSettings, vuetifyInputsSettingsKey } from './settings';\n\nconst props = defineProps<MessagesWidgetProps>();\nconst settings = inject<VuetifyInputsSettings>(vuetifyInputsSettingsKey, {});\n\nconst htmlElements = new Set([\n 'div',\n 'span',\n 'p',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'section',\n 'article',\n 'aside',\n 'nav',\n 'header',\n 'footer',\n 'main',\n 'figure',\n 'figcaption',\n 'blockquote',\n 'pre',\n 'code',\n 'em',\n 'strong',\n 'small',\n 'mark',\n 'del',\n 'ins',\n 'sub',\n 'sup',\n 'i',\n 'b',\n 'u',\n 's',\n 'a',\n 'img',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'option',\n 'label',\n 'form',\n 'table',\n 'tr',\n 'td',\n 'th',\n 'thead',\n 'tbody',\n 'tfoot',\n 'ul',\n 'ol',\n 'li',\n 'dl',\n 'dt',\n 'dd',\n]);\n\nfunction asRenderable(msg: RenderableValue | ErrorInput): RenderableValue {\n return msg instanceof RenderableValue ? msg : new RenderableValue(errorText(msg, settings));\n}\n\nfunction renderComponent(name: string, bindings: Record<string, any>, children: readonly RenderContentNonCallable[]) {\n const childNodes = () => children.map(renderChild);\n // a common html element is rendered as itself, with the children as its own; any other name is resolved as a\n // registered component, with the children as its default slot\n if (htmlElements.has(name.toLowerCase())) return h(name, bindings, childNodes());\n return h(resolveComponent(name), bindings, children.length ? { default: childNodes } : undefined);\n}\n\n// a child of a component: text as a text node, an HtmlString in a span, so that it fits in an inline element\nfunction renderChild(child: RenderContentNonCallable): VNodeChild {\n const msg = new RenderableValue(child);\n switch (msg.componentName) {\n case 'template':\n return msg.componentBody;\n case 'html':\n return h('span', { innerHTML: msg.componentBody });\n case 'vue-markdown': {\n const { source, options, plugins } = msg.componentBindings;\n return h(VueMarkdown, { class: 'df-messages-widget-markdown', source, options, plugins });\n }\n default:\n return renderComponent(msg.componentName, msg.componentBindings, msg.componentChildren);\n }\n}\n\nconst render = () => {\n if (typeof props.message === 'string') return h('span', { class: props.classes }, props.message);\n return props.message.map((item) => {\n const msg = asRenderable(item);\n const classes = [props.classes, msg.extraClasses];\n switch (msg.componentName) {\n case 'template':\n return h('div', { class: classes }, msg.componentBody);\n case 'html':\n return h('div', { class: classes, innerHTML: msg.componentBody });\n case 'vue-markdown': {\n const { source, options, plugins } = msg.componentBindings;\n return h(VueMarkdown, { class: [...classes, 'df-messages-widget-markdown'], source, options, plugins });\n }\n default:\n return renderComponent(\n msg.componentName,\n { ...msg.componentBindings, class: [classes, msg.componentBindings.class] },\n msg.componentChildren,\n );\n }\n });\n};\n</script>\n\n<style>\n/* no margins for markdown at the very top and very bottom */\n.df-messages-widget-markdown > :first-child,\n.df-messages-widget-markdown > :last-child {\n margin-top: 0 !important;\n padding-top: 0 !important;\n margin-bottom: 0 !important;\n padding-bottom: 0 !important;\n line-height: 1.35em !important;\n}\n</style>\n","<template>\n <render />\n</template>\n\n<script setup lang=\"ts\">\nimport { h, inject, resolveComponent, type VNodeChild } from 'vue';\nimport VueMarkdown from 'vue-markdown-render';\n\nimport type { MessagesWidgetProps } from '../dynamicforms-component-props';\n\nimport { type ErrorInput, errorText } from './error-text';\nimport { RenderableValue, type RenderContentNonCallable } from './render-content';\nimport { type VuetifyInputsSettings, vuetifyInputsSettingsKey } from './settings';\n\nconst props = defineProps<MessagesWidgetProps>();\nconst settings = inject<VuetifyInputsSettings>(vuetifyInputsSettingsKey, {});\n\nconst htmlElements = new Set([\n 'div',\n 'span',\n 'p',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'section',\n 'article',\n 'aside',\n 'nav',\n 'header',\n 'footer',\n 'main',\n 'figure',\n 'figcaption',\n 'blockquote',\n 'pre',\n 'code',\n 'em',\n 'strong',\n 'small',\n 'mark',\n 'del',\n 'ins',\n 'sub',\n 'sup',\n 'i',\n 'b',\n 'u',\n 's',\n 'a',\n 'img',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'option',\n 'label',\n 'form',\n 'table',\n 'tr',\n 'td',\n 'th',\n 'thead',\n 'tbody',\n 'tfoot',\n 'ul',\n 'ol',\n 'li',\n 'dl',\n 'dt',\n 'dd',\n]);\n\nfunction asRenderable(msg: RenderableValue | ErrorInput): RenderableValue {\n return msg instanceof RenderableValue ? msg : new RenderableValue(errorText(msg, settings));\n}\n\nfunction renderComponent(name: string, bindings: Record<string, any>, children: readonly RenderContentNonCallable[]) {\n const childNodes = () => children.map(renderChild);\n // a common html element is rendered as itself, with the children as its own; any other name is resolved as a\n // registered component, with the children as its default slot\n if (htmlElements.has(name.toLowerCase())) return h(name, bindings, childNodes());\n return h(resolveComponent(name), bindings, children.length ? { default: childNodes } : undefined);\n}\n\n// a child of a component: text as a text node, an HtmlString in a span, so that it fits in an inline element\nfunction renderChild(child: RenderContentNonCallable): VNodeChild {\n const msg = new RenderableValue(child);\n switch (msg.componentName) {\n case 'template':\n return msg.componentBody;\n case 'html':\n return h('span', { innerHTML: msg.componentBody });\n case 'vue-markdown': {\n const { source, options, plugins } = msg.componentBindings;\n return h(VueMarkdown, { class: 'df-messages-widget-markdown', source, options, plugins });\n }\n default:\n return renderComponent(msg.componentName, msg.componentBindings, msg.componentChildren);\n }\n}\n\nconst render = () => {\n if (typeof props.message === 'string') return h('span', { class: props.classes }, props.message);\n return props.message.map((item) => {\n const msg = asRenderable(item);\n const classes = [props.classes, msg.extraClasses];\n switch (msg.componentName) {\n case 'template':\n return h('div', { class: classes }, msg.componentBody);\n case 'html':\n return h('div', { class: classes, innerHTML: msg.componentBody });\n case 'vue-markdown': {\n const { source, options, plugins } = msg.componentBindings;\n return h(VueMarkdown, { class: [...classes, 'df-messages-widget-markdown'], source, options, plugins });\n }\n default:\n return renderComponent(\n msg.componentName,\n { ...msg.componentBindings, class: [classes, msg.componentBindings.class] },\n msg.componentChildren,\n );\n }\n });\n};\n</script>\n\n<style>\n/* no margins for markdown at the very top and very bottom */\n.df-messages-widget-markdown > :first-child,\n.df-messages-widget-markdown > :last-child {\n margin-top: 0 !important;\n padding-top: 0 !important;\n margin-bottom: 0 !important;\n padding-bottom: 0 !important;\n line-height: 1.35em !important;\n}\n</style>\n","<template>\n <messages-widget :message=\"widgetMessage\" :classes=\"widgetClasses\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\nimport type { DfInputHintProps } from '../dynamicforms-component-props';\n\nimport MessagesWidget from './messages-widget.vue';\nimport { RenderableValue } from './render-content';\n\nconst props = withDefaults(defineProps<DfInputHintProps>(), {\n errors: '',\n message: '',\n errorClasses: 'text-error',\n messageClasses: '',\n});\n\nconst isError = computed(() => {\n if (props.errors) {\n if (typeof props.errors === 'string') {\n return props.errors.trim().length > 0;\n }\n return props.errors.length > 0;\n }\n return false;\n});\n\nconst widgetMessage = computed(() => {\n if (isError.value) return props.errors;\n const message = props.message;\n if (typeof message === 'string' || Array.isArray(message)) return message;\n return [new RenderableValue(message as Exclude<typeof message, readonly RenderableValue[]>)];\n});\n\nconst widgetClasses = computed(() => {\n return isError.value ? props.errorClasses : props.messageClasses;\n});\n</script>\n\n<style scoped></style>\n","<template>\n <messages-widget :message=\"widgetMessage\" :classes=\"widgetClasses\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\nimport type { DfInputHintProps } from '../dynamicforms-component-props';\n\nimport MessagesWidget from './messages-widget.vue';\nimport { RenderableValue } from './render-content';\n\nconst props = withDefaults(defineProps<DfInputHintProps>(), {\n errors: '',\n message: '',\n errorClasses: 'text-error',\n messageClasses: '',\n});\n\nconst isError = computed(() => {\n if (props.errors) {\n if (typeof props.errors === 'string') {\n return props.errors.trim().length > 0;\n }\n return props.errors.length > 0;\n }\n return false;\n});\n\nconst widgetMessage = computed(() => {\n if (isError.value) return props.errors;\n const message = props.message;\n if (typeof message === 'string' || Array.isArray(message)) return message;\n return [new RenderableValue(message as Exclude<typeof message, readonly RenderableValue[]>)];\n});\n\nconst widgetClasses = computed(() => {\n return isError.value ? props.errorClasses : props.messageClasses;\n});\n</script>\n\n<style scoped></style>\n","<template>\n <div class=\"df-label\" :class=\"{ 'allow-wrap': allowWrap }\">\n <template v-if=\"label.icon\">\n <cached-icon v-if=\"label.iconComponent === 'v-icon'\" :name=\"label.icon\" size=\"1.25em\" />\n <v-img v-else-if=\"label.iconComponent === 'v-img'\" class=\"icon\" :src=\"label.icon\" />\n <component :is=\"label.iconComponent\" v-else :src=\"label.icon\" />\n </template>\n <template v-if=\"typeof lbl === 'string'\">{{ lbl }}</template>\n <messages-widget v-else :message=\"[content]\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport type { DfLabelProps } from '../dynamicforms-component-props';\n\nimport MessagesWidget from './messages-widget.vue';\nimport { RenderableValue } from './render-content';\n\nconst props = defineProps<DfLabelProps>();\n\n// the label's own content: the slot data holds only its text, which Vuetify is given\nconst lbl = computed(() => props.label.text || props.data?.label || '');\nconst content = computed(() => new RenderableValue(lbl.value));\n</script>\n\n<style>\n.df-label {\n display: flex;\n align-items: center;\n gap: 2px;\n white-space: nowrap;\n justify-content: flex-start;\n}\n\n.df-label.allow-wrap {\n white-space: initial;\n}\n\n.df-label .icon {\n width: 1.25em;\n}\n\n.df-label .df-messages-widget-markdown :first-child,\n.df-label .df-messages-widget-markdown :last-child {\n margin-top: 0 !important;\n padding-top: 0 !important;\n margin-bottom: 0 !important;\n padding-bottom: 0 !important;\n line-height: 1.35em !important; /* inspired by vitepress' aggressive settings */\n}\n</style>\n","<template>\n <div class=\"df-label\" :class=\"{ 'allow-wrap': allowWrap }\">\n <template v-if=\"label.icon\">\n <cached-icon v-if=\"label.iconComponent === 'v-icon'\" :name=\"label.icon\" size=\"1.25em\" />\n <v-img v-else-if=\"label.iconComponent === 'v-img'\" class=\"icon\" :src=\"label.icon\" />\n <component :is=\"label.iconComponent\" v-else :src=\"label.icon\" />\n </template>\n <template v-if=\"typeof lbl === 'string'\">{{ lbl }}</template>\n <messages-widget v-else :message=\"[content]\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport type { DfLabelProps } from '../dynamicforms-component-props';\n\nimport MessagesWidget from './messages-widget.vue';\nimport { RenderableValue } from './render-content';\n\nconst props = defineProps<DfLabelProps>();\n\n// the label's own content: the slot data holds only its text, which Vuetify is given\nconst lbl = computed(() => props.label.text || props.data?.label || '');\nconst content = computed(() => new RenderableValue(lbl.value));\n</script>\n\n<style>\n.df-label {\n display: flex;\n align-items: center;\n gap: 2px;\n white-space: nowrap;\n justify-content: flex-start;\n}\n\n.df-label.allow-wrap {\n white-space: initial;\n}\n\n.df-label .icon {\n width: 1.25em;\n}\n\n.df-label .df-messages-widget-markdown :first-child,\n.df-label .df-messages-widget-markdown :last-child {\n margin-top: 0 !important;\n padding-top: 0 !important;\n margin-bottom: 0 !important;\n padding-bottom: 0 !important;\n line-height: 1.35em !important; /* inspired by vitepress' aggressive settings */\n}\n</style>\n","import type { FieldBase, ValidationError } from '@dynamicforms/vue-forms';\nimport { computed, type ComputedRef, inject, type MaybeRefOrGetter, toValue } from 'vue';\n\nimport { type VuetifyInputsSettings, vuetifyInputsSettingsKey } from './settings';\n\n/**\n * The errors of `errors` a component shows now.\n *\n * By default an error is shown where `control` is sent - its `effectiveAccess` is not `'disabled'` - and either its\n * `origin` is `'server'` or the element is `touched`.\n * Without a control, `touched` is the component's own. The `shownErrors` setting replaces the rule with a condition\n * of the application's own, asked for each error with the default answer.\n */\nexport function selectShownErrors(\n errors: readonly ValidationError[],\n control: FieldBase | undefined,\n touched: boolean,\n settings: VuetifyInputsSettings,\n): ValidationError[] {\n const sent = !control || control.effectiveAccess !== 'disabled';\n return errors.filter((error) => {\n const shownByDefault = sent && (error.origin === 'server' || touched);\n return settings.shownErrors ? settings.shownErrors(error, control, shownByDefault) : shownByDefault;\n });\n}\n\n/**\n * The errors of `element` to show now, by the rule `selectShownErrors` states and the `shownErrors` setting the\n * application provided. It is what a template rendering errors of its own - a group's, say - binds, so that they\n * appear when the inputs' errors do. Call it in a component's setup, where the settings are injected.\n */\nexport function useShownErrors(element: MaybeRefOrGetter<FieldBase | undefined>): ComputedRef<ValidationError[]> {\n const settings = inject<VuetifyInputsSettings>(vuetifyInputsSettingsKey, {});\n return computed(() => {\n const control = toValue(element);\n return control ? selectShownErrors(control.errors, control, control.touched, settings) : [];\n });\n}\n","import Form, { ValidationError } from '@dynamicforms/vue-forms';\nimport { isEmpty } from 'lodash-es';\nimport { computed, type ComputedRef, inject, nextTick, type Ref, ref, shallowRef, toRaw } from 'vue';\n\nimport { type ErrorInput, toErrorDescription } from './error-text';\nimport { type RenderContentNonCallable, renderContentText } from './render-content';\nimport { VuetifyInputsSettings, vuetifyInputsSettingsKey } from './settings';\nimport { selectShownErrors } from './shown-errors';\n\n/** A field's label: its content, and an icon shown before it. */\nexport class Label {\n constructor(\n public text: RenderContentNonCallable,\n public icon?: string,\n public iconComponent: string = 'v-icon',\n ) {}\n}\n\nexport type FieldVariant = 'outlined' | 'plain' | 'underlined' | 'filled' | 'solo' | 'solo-inverted' | 'solo-filled';\nexport type VuetifyDensity = 'default' | 'comfortable' | 'compact';\nexport type FieldDensity = 'default' | 'comfortable' | 'compact' | 'inline';\n/** Vuetify's own `size` prop (`v-btn`, `v-icon`, ...) also accepts an arbitrary CSS length or number, so this\n * keeps that but still offers the named sizes for autocomplete: `(string & {})` is a plain `string` to the type\n * checker (any string is still assignable) but not to a union with string literals, which is what makes an IDE\n * suggest the literals instead of collapsing them into `string`. */\nexport type VuetifyButtonSize = 'x-small' | 'small' | 'default' | 'large' | 'x-large' | (string & {}) | number;\n\n/**\n * The presentation an element carries for the components in this library.\n *\n * Every one of these is also a prop, and the prop wins where both state something: a call site is more specific\n * than the element it renders. What the element carries is what a form declared in code says about itself, so a\n * field that names its own label needs no attribute at the tag that draws it.\n *\n * `Extras` is @dynamicforms/vue-forms' augmentation point for exactly this, so these properties are typed on every\n * element in an application that installs this library, the fields written inline in a `Group` declaration\n * included.\n */\ndeclare module '@dynamicforms/vue-forms' {\n interface Extras {\n label?: RenderContentNonCallable | Label;\n placeholder?: string;\n helpText?: string;\n hint?: string;\n cssClass?: string;\n density?: FieldDensity;\n variant?: FieldVariant;\n }\n}\n\nexport interface BaseProps<T = any> {\n control?: Form.FieldBase<T>;\n modelValue?: T;\n label?: RenderContentNonCallable | Label;\n errors?: ErrorInput[];\n placeholder?: string;\n helpText?: string;\n hint?: string;\n enabled?: boolean;\n visibility?: Form.Visibility;\n cssClass?: string;\n clearable?: boolean;\n passthroughAttrs?: Record<string, any>;\n density?: FieldDensity;\n variant?: FieldVariant;\n}\n\nexport const defaultBaseProps = { enabled: undefined, clearable: true };\n\n/** What `InputBase`'s `default` slot receives: Vuetify's `v-field` slot props. `prepend-inner` receives them without\n * `props`. */\nexport interface InputBaseSlotProps {\n /** Attributes for the control: its `id`, `class` and ARIA attributes. */\n props: Record<string, unknown>;\n isActive: Ref<boolean>;\n isFocused: Ref<boolean>;\n iconColor: ComputedRef<string | undefined>;\n controlRef: Ref<HTMLElement | undefined>;\n /** Sets the field's focused state. */\n focus: () => void;\n /** Clears the field's focused state. */\n blur: () => void;\n}\n\nexport interface BaseEmits<T = any> {\n (e: 'update:modelValue', value: T): void;\n (e: 'click:clear'): void;\n}\n\n/**\n * The state and Vuetify bindings an input shares with every other input. `componentErrors` are the errors the\n * component finds in the value itself, reported where no `control` is bound; a bound control reports through its\n * own validators.\n */\nexport function useInputBase<T = any>(\n props: BaseProps<T>,\n emit: BaseEmits<T>,\n componentErrors?: () => ValidationError[],\n) {\n const settings = inject<VuetifyInputsSettings>(vuetifyInputsSettingsKey, {});\n const injectedDensity = inject<FieldDensity | null>('field-density', null);\n const injectedVariant = inject<FieldVariant | null>('field-variant', null);\n const internalValue = ref<T | null>(null);\n\n // A write is not a statement about what the control ends up holding. A ValueChangedAction may write a different value\n // back, and a handler that throws unwinds it. The rendered control has the written value in its DOM by then, so it is\n // the read here that has to correct it - and where the value the control ends up holding is the one it started with,\n // as under a rule that puts back the five characters a six-character write exceeded, the read does not move and Vue\n // schedules no render at all. Holding the written value for one tick makes the read change twice, so the repaint that\n // restores what the control holds happens.\n const pendingWrite = shallowRef<{ value: T } | null>(null);\n\n const value = computed({\n get(): T {\n if (pendingWrite.value) return pendingWrite.value.value;\n if (props.control) return props.control.value as T;\n if (props.modelValue === undefined) return internalValue.value as T;\n return props.modelValue as T;\n },\n set(newValue: T) {\n try {\n if (props.control) props.control.value = newValue;\n } finally {\n // compared as the write was made: an element holds its state behind reactive(), so an array or an object\n // reads back as a proxy of what was written and an identity comparison would answer that every such write\n // was refused. Object.is over the raw objects answers for NaN as well\n if (props.control && !Object.is(toRaw(props.control.value as any), toRaw(newValue as any))) {\n pendingWrite.value = { value: newValue };\n nextTick(() => {\n pendingWrite.value = null;\n });\n }\n }\n if (props.modelValue === undefined) internalValue.value = newValue;\n emit('update:modelValue', props.control ? (props.control.value as T) : newValue);\n },\n });\n\n if (props.control && !(props.control instanceof Form.FieldBase)) {\n throw new Error('control prop is not a vue-form control instance');\n }\n\n const controlTouch = computed({\n get() {\n return props.control!.touched;\n },\n set(val: boolean) {\n props.control!.touched = val;\n },\n });\n const touched = props.control ? controlTouch : ref(false);\n const valid = computed(() => (props.control ? props.control.valid : true));\n // an error of the errors prop is selected as a ValidationError and rendered as it was given\n const givenErrors = computed(() => {\n const given = new Map<ValidationError, ErrorInput>();\n (props.errors ?? []).forEach((input) => {\n const { code, params, detail, origin } = toErrorDescription(input);\n given.set(new ValidationError(code, params, detail, origin), input);\n });\n return given;\n });\n const errors = computed(() =>\n props.control ? props.control.errors : [...givenErrors.value.keys(), ...(componentErrors?.() ?? [])],\n );\n // what the user is shown, by the rule selectShownErrors states and the application's shownErrors setting\n const shownErrors = computed((): ErrorInput[] =>\n selectShownErrors(errors.value, props.control, touched.value, settings).map(\n (error) => givenErrors.value.get(error) ?? error,\n ),\n );\n const anyErrors = computed(() => (shownErrors.value.length > 0 ? ' ' : undefined));\n // a field inside a disabled section is drawn disabled: effectiveEnabled is false where the element or any\n // container above it is disabled, which is the question a rendered input asks\n const enabled = computed(() => (props.control ? props.control.effectiveEnabled : props.enabled !== false));\n // A control states its own visibility - vue-forms refuses anything that is not one of the four. The prop is held to\n // the same, so an unrecognised visibility is refused here as loudly as it is there.\n const visibility = computed((): Form.Visibility => {\n if (props.control) return props.control.visibility;\n if (props.visibility == null) return Form.defaultVisibility;\n if (!Form.isVisibility(props.visibility)) {\n throw new Error(`'${props.visibility}' is not a visibility: ${Form.visibilityValues.join(', ')}`);\n }\n return props.visibility;\n });\n const isRendered = computed(() => visibility.value !== 'suppress');\n const visibilityClass = computed(() => ({\n 'd-none': visibility.value === 'hidden',\n invisible: visibility.value === 'invisible',\n }));\n // the presentation the bound element carries: what a prop does not state is taken from here before any default\n const extra = computed(() => props.control?.extra ?? {});\n\n const label = computed((): Label => {\n const stated = props.label ?? extra.value.label;\n return stated instanceof Label ? stated : new Label(stated ?? '');\n });\n const placeholder = computed(() => props.placeholder ?? extra.value.placeholder ?? '');\n const helpText = computed(() => props.helpText ?? extra.value.helpText ?? '');\n const hint = computed(() => props.hint ?? extra.value.hint ?? '');\n const cssClass = computed(() => props.cssClass ?? extra.value.cssClass ?? '');\n\n const density = computed(\n (): FieldDensity => props.density ?? extra.value.density ?? injectedDensity ?? settings.defaultDensity ?? 'default',\n );\n const boundDensity = computed((): VuetifyDensity => (density.value === 'inline' ? 'default' : density.value));\n const variant = computed(\n (): FieldVariant =>\n props.variant ?? extra.value.variant ?? injectedVariant ?? settings.defaultVariant ?? 'underlined',\n );\n\n return {\n value,\n valid,\n enabled,\n errors,\n shownErrors,\n visibility,\n isRendered,\n visibilityClass,\n label,\n touched,\n density,\n densityClass: computed(() => `df-density-${density.value}`),\n\n vuetifyBindings: computed(() => ({\n name: props.control?.fieldName,\n class: cssClass.value,\n\n density: boundDensity.value,\n variant: variant.value,\n\n label: renderContentText(label.value.text),\n errorMessages: anyErrors.value,\n // 'error-count': errors?.value.length || 0,\n readonly: !enabled.value,\n disabled: !enabled.value,\n\n placeholder: placeholder.value,\n 'persistent-placeholder': !isEmpty(placeholder.value),\n\n hint: hint.value,\n persistentHint: true, // we want persistent hint always\n hideDetails: <boolean | 'auto' | undefined>'auto', // we want to hide the hint element when hint isn't there\n helpText: helpText.value,\n\n ...(props.passthroughAttrs || {}),\n })),\n };\n}\n","<template>\n <v-input\n v-if=\"isRendered\"\n :name=\"vuetifyBindings.name\"\n :density=\"vuetifyBindings.density\"\n :hint=\"vuetifyBindings.hint\"\n :persistent-hint=\"vuetifyBindings.persistentHint\"\n :hide-details=\"vuetifyBindings.hideDetails\"\n :error-messages=\"vuetifyBindings.errorMessages\"\n :class=\"[cssClass, visibilityClass]\"\n >\n <v-field\n :variant=\"vuetifyBindings.variant\"\n :density=\"vuetifyBindings.density\"\n :label=\"vuetifyBindings.label\"\n :disabled=\"vuetifyBindings.disabled\"\n :clearable=\"isClearable\"\n :persistent-clear=\"true\"\n :dirty=\"!!value || !!vuetifyBindings.placeholder\"\n :active=\"focused\"\n :loading=\"loading\"\n @click:clear=\"emits('click:clear')\"\n @update:focused=\"(isFocused) => setFocused(isFocused)\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #default=\"slotProps\">\n <div class=\"d-flex w-100 df-style-resetting df-sub-field\"><slot v-bind=\"slotProps\" /></div>\n </template>\n <template #loader=\"loaderProps\"><slot name=\"loader\" v-bind=\"loaderProps\" /></template>\n <template v-if=\"$slots['prepend-inner']\" #prepend-inner=\"prependInnerProps\">\n <slot name=\"prepend-inner\" v-bind=\"prependInnerProps\" />\n </template>\n </v-field>\n <template #message=\"{ message }\">\n <df-input-hint :message=\"message\" :errors=\"shownErrors\" />\n </template>\n <template v-if=\"$slots.prepend\" #prepend=\"prependProps\"><slot name=\"prepend\" v-bind=\"prependProps\" /></template>\n </v-input>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, unref } from 'vue';\n\nimport DfInputHint from './df-input-hint.vue';\nimport DfLabel from './df-label.vue';\nimport { BaseEmits, BaseProps, type InputBaseSlotProps, useInputBase } from './input-base';\n\nconst props = defineProps<BaseProps & { loading?: boolean }>();\nconst emits = defineEmits<BaseEmits & { (e: 'blur'): void }>();\n// declared here, so the emitted declarations do not name Vuetify's internal slot types\ndefineSlots<{\n default?(props: InputBaseSlotProps): any;\n 'prepend-inner'?(props: Omit<InputBaseSlotProps, 'props'>): any;\n loader?(props: Record<string, unknown>): any;\n prepend?(props: Record<string, unknown>): any;\n}>();\n\nconst { isRendered, label, shownErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(props, emits);\n\nconst isClearable = computed(() => !!(unref(props.clearable) && unref(value)));\nconst focused = ref<boolean>(false);\n\nfunction setFocused(isFocused: boolean) {\n focused.value = isFocused;\n if (!isFocused) {\n touched.value = true;\n emits('blur');\n }\n}\n</script>\n\n<style>\n.df-style-resetting .v-field__overlay {\n background-color: transparent;\n}\n.df-style-resetting .v-field__outline::before,\n.df-style-resetting .v-field__outline::after {\n content: none !important;\n}\n\n.df-sub-field {\n max-height: var(--v-input-control-height);\n min-height: max(\n var(--v-input-control-height, 56px),\n 1.5rem + var(--v-field-input-padding-top) + var(--v-field-input-padding-bottom)\n );\n}\n\n.df-density-inline .df-sub-field {\n min-height: revert;\n}\n\n.rtf-editor .df-sub-field {\n max-height: revert;\n}\n</style>\n","<template>\n <v-input\n v-if=\"isRendered\"\n :name=\"vuetifyBindings.name\"\n :density=\"vuetifyBindings.density\"\n :hint=\"vuetifyBindings.hint\"\n :persistent-hint=\"vuetifyBindings.persistentHint\"\n :hide-details=\"vuetifyBindings.hideDetails\"\n :error-messages=\"vuetifyBindings.errorMessages\"\n :class=\"[cssClass, visibilityClass]\"\n >\n <v-field\n :variant=\"vuetifyBindings.variant\"\n :density=\"vuetifyBindings.density\"\n :label=\"vuetifyBindings.label\"\n :disabled=\"vuetifyBindings.disabled\"\n :clearable=\"isClearable\"\n :persistent-clear=\"true\"\n :dirty=\"!!value || !!vuetifyBindings.placeholder\"\n :active=\"focused\"\n :loading=\"loading\"\n @click:clear=\"emits('click:clear')\"\n @update:focused=\"(isFocused) => setFocused(isFocused)\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #default=\"slotProps\">\n <div class=\"d-flex w-100 df-style-resetting df-sub-field\"><slot v-bind=\"slotProps\" /></div>\n </template>\n <template #loader=\"loaderProps\"><slot name=\"loader\" v-bind=\"loaderProps\" /></template>\n <template v-if=\"$slots['prepend-inner']\" #prepend-inner=\"prependInnerProps\">\n <slot name=\"prepend-inner\" v-bind=\"prependInnerProps\" />\n </template>\n </v-field>\n <template #message=\"{ message }\">\n <df-input-hint :message=\"message\" :errors=\"shownErrors\" />\n </template>\n <template v-if=\"$slots.prepend\" #prepend=\"prependProps\"><slot name=\"prepend\" v-bind=\"prependProps\" /></template>\n </v-input>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, unref } from 'vue';\n\nimport DfInputHint from './df-input-hint.vue';\nimport DfLabel from './df-label.vue';\nimport { BaseEmits, BaseProps, type InputBaseSlotProps, useInputBase } from './input-base';\n\nconst props = defineProps<BaseProps & { loading?: boolean }>();\nconst emits = defineEmits<BaseEmits & { (e: 'blur'): void }>();\n// declared here, so the emitted declarations do not name Vuetify's internal slot types\ndefineSlots<{\n default?(props: InputBaseSlotProps): any;\n 'prepend-inner'?(props: Omit<InputBaseSlotProps, 'props'>): any;\n loader?(props: Record<string, unknown>): any;\n prepend?(props: Record<string, unknown>): any;\n}>();\n\nconst { isRendered, label, shownErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(props, emits);\n\nconst isClearable = computed(() => !!(unref(props.clearable) && unref(value)));\nconst focused = ref<boolean>(false);\n\nfunction setFocused(isFocused: boolean) {\n focused.value = isFocused;\n if (!isFocused) {\n touched.value = true;\n emits('blur');\n }\n}\n</script>\n\n<style>\n.df-style-resetting .v-field__overlay {\n background-color: transparent;\n}\n.df-style-resetting .v-field__outline::before,\n.df-style-resetting .v-field__outline::after {\n content: none !important;\n}\n\n.df-sub-field {\n max-height: var(--v-input-control-height);\n min-height: max(\n var(--v-input-control-height, 56px),\n 1.5rem + var(--v-field-input-padding-top) + var(--v-field-input-padding-bottom)\n );\n}\n\n.df-density-inline .df-sub-field {\n min-height: revert;\n}\n\n.rtf-editor .df-sub-field {\n max-height: revert;\n}\n</style>\n","import { createTranslatable, type Translatable } from '@dynamicforms/translatable';\nimport { getCurrentInstance, inject } from 'vue';\n\nimport { type VuetifyInputsSettings, vuetifyInputsSettingsKey } from './settings';\n\nconst defaults = {\n Yes: 'Yes',\n No: 'No',\n Close: 'Close',\n Cancel: 'Cancel',\n Ok: 'OK',\n Paragraph: 'Paragraph',\n Heading1: 'Heading 1',\n Heading2: 'Heading 2',\n Heading3: 'Heading 3',\n Heading4: 'Heading 4',\n Heading5: 'Heading 5',\n Heading6: 'Heading 6',\n Downloadable: 'Downloadable',\n ArticleCategory: 'Article category',\n Title: 'Title',\n Subtitle: 'Subtitle',\n InfoBox: 'Info box',\n SideQuote: 'Side quote',\n Marker: 'Marker',\n Spoiler: 'Spoiler',\n CodeDark: 'Code (dark)',\n CodeBright: 'Code (bright)',\n Undo: 'Undo',\n Redo: 'Redo',\n SelectAll: 'Select all',\n Bold: 'Bold',\n Italic: 'Italic',\n HorizontalLine: 'Horizontal line',\n Blockquote: 'Block quote',\n BulletedList: 'Bulleted list',\n NumberedList: 'Numbered list',\n Outdent: 'Decrease indent',\n Indent: 'Increase indent',\n AlignLeft: 'Align left',\n AlignCenter: 'Align center',\n AlignRight: 'Align right',\n AlignJustify: 'Justify',\n Link: 'Link',\n LinkUrl: 'URL',\n LinkApply: 'Apply',\n LinkRemove: 'Remove link',\n Image: 'Image',\n ImageUrl: 'Image URL',\n ImageUpload: 'Upload image',\n ImageInsert: 'Insert',\n ImageDropHint: 'Drop image here or click to browse',\n ImageReplace: 'Replace image',\n ImageDownload: 'Download image',\n FileDownload: 'Download file',\n Table: 'Table',\n TableInsert: 'Insert table',\n TableAddRowAbove: 'Add row above',\n TableAddRowBelow: 'Add row below',\n TableDeleteRow: 'Delete row',\n TableAddColumnBefore: 'Add column before',\n TableAddColumnAfter: 'Add column after',\n TableDeleteColumn: 'Delete column',\n TableToggleHeaderRow: 'Toggle header row',\n TableDeleteTable: 'Delete table',\n Style: 'Style',\n MediaEmbed: 'Insert media',\n MediaEmbedUrl: 'Video URL',\n MediaEmbedInsert: 'Insert',\n};\n\ntype Key = keyof typeof defaults;\n\nconst global = createTranslatable(defaults);\n\n/**\n * Sets the translation function of the library's strings for the whole process; see `@dynamicforms/translatable`.\n * An app installed with the `translate` setting translates with that one instead.\n */\nexport const { translateStrings } = global;\n\n// one Translatable per settings object that states `translate`, made on first use\nconst perApp = new WeakMap<VuetifyInputsSettings, Translatable<typeof defaults>>();\n\nfunction translatableOf(settings: VuetifyInputsSettings | undefined): Translatable<typeof defaults> {\n if (!settings?.translate) return global;\n let translatable = perApp.get(settings);\n if (!translatable) {\n translatable = createTranslatable(defaults);\n translatable.translateStrings(settings.translate, settings.translateNamespace);\n perApp.set(settings, translatable);\n }\n return translatable;\n}\n\n/**\n * The current translation of one of the library's strings. Called while a component sets up or renders, it\n * translates with the `translate` setting the component reads, as it reads every other setting, where one is given,\n * and with the function `translateStrings` set otherwise. Under server-side rendering each request's app states its\n * own `translate`. An event handler or a timer reads no setting; it uses `useTranslate()`.\n */\nexport function translate(key: Key, params?: Record<string, unknown>): string {\n const settings = getCurrentInstance() ? inject<VuetifyInputsSettings>(vuetifyInputsSettingsKey, {}) : undefined;\n return translatableOf(settings).translate(key, params);\n}\n\n/**\n * `translate` bound to the settings the calling component reads, for use outside its setup and render: in an event\n * handler or a timer. Called in a component's setup.\n */\nexport function useTranslate(): (key: Key, params?: Record<string, unknown>) => string {\n const translatable = translatableOf(inject<VuetifyInputsSettings>(vuetifyInputsSettingsKey, {}));\n return (key, params) => translatable.translate(key, params);\n}\n","/**\n * How an action is rendered: `'button'` as a tonal `<v-btn>`, `'text'` as a text-variant `<v-btn>`.\n */\nexport type ActionDisplayStyle = 'button' | 'text';\n\n/** every display style */\nexport const actionDisplayStyles: readonly ActionDisplayStyle[] = Object.freeze(['button', 'text']);\n\n/** What an action renders as where nothing states otherwise. */\nexport const defaultDisplayStyle: ActionDisplayStyle = 'button';\n\n/** Answers whether `value` is one of the display styles. */\nexport function isActionDisplayStyle(value: unknown): value is ActionDisplayStyle {\n return (actionDisplayStyles as readonly unknown[]).includes(value);\n}\n","import { isPlainObject } from 'lodash-es';\nimport { computed } from 'vue';\nimport { useDisplay } from 'vuetify';\n\nexport const responsiveBreakpoints = ['xs', 'sm', 'md', 'lg', 'xl'] as const;\nexport type BreakpointNames = (typeof responsiveBreakpoints)[number];\n/**\n * A set of options and the per-breakpoint sets that restate parts of it. `B` is what a breakpoint may state,\n * and defaults to the whole of `T`; a subclass narrows it where a member belongs to the object as a whole rather\n * than to one screen width.\n */\nexport type BreakpointsJSON<T extends Record<string, any>, B extends Record<string, any> = T> = T &\n Partial<Record<BreakpointNames, B>>;\n\nexport abstract class ResponsiveRenderOptions<T extends Record<string, any>> {\n protected readonly _value: BreakpointsJSON<T>;\n\n constructor(data?: BreakpointsJSON<T>) {\n this._value = this.cleanBreakpoint(data as T, true)!;\n if (data) {\n responsiveBreakpoints.forEach((bp) => {\n const options = this.cleanBreakpoint(data[bp]);\n if (options) this._value[bp] = options;\n });\n }\n }\n\n getOptionsForBreakpoint(breakpoint: BreakpointNames): T {\n // a base that states nothing cleans to null, and the breakpoints above it still have options to resolve\n const result = (this.cleanBreakpoint(this._value as T) ?? ({} as T)) as BreakpointsJSON<T>;\n for (const bp of responsiveBreakpoints) {\n // the fields that cascade are the ones each breakpoint states, so a field named at a breakpoint and\n // nowhere else still reaches the result\n const bpData = this._value[bp] ?? {};\n for (const field of Object.keys(bpData)) {\n const value = (<any>bpData)[field];\n // a breakpoint states what it changes; a field it says nothing about keeps cascading\n if (value == null) continue;\n if (isPlainObject(value)) {\n // shallow, so a breakpoint restates single keys of an options object rather than the whole of it. A\n // nested object is a value like any other and is replaced whole. Only plain objects merge: a Date, a\n // Map or a class instance would come out of a spread as its own properties without its prototype.\n (<any>result)[field] = { ...(<any>result)[field], ...value };\n } else {\n (<any>result)[field] = value;\n }\n }\n if (bp === breakpoint) break;\n }\n return result;\n }\n\n /**\n * Normalizes one breakpoint's options. The merge reads `null` and `undefined` as \"this breakpoint says\n * nothing about that field\", so a field the breakpoint does not state has to come back as `undefined` rather\n * than as an empty value - an empty array or string returned here reads as a breakpoint deliberately emptying\n * what it inherited.\n */\n protected abstract cleanBreakpoint(bp?: T, defaultIfEmpty?: boolean): T | null;\n}\n\nexport function getBreakpointName(dp: ReturnType<typeof useDisplay>): BreakpointNames {\n if (dp.xlAndUp.value) return 'xl';\n if (dp.lgAndUp.value) return 'lg';\n if (dp.mdAndUp.value) return 'md';\n if (dp.smAndUp.value) return 'sm';\n return 'xs';\n}\n\nexport function useBreakpoint() {\n const display = useDisplay();\n\n return computed<BreakpointNames>(() => getBreakpointName(display));\n}\n","import { ActionValue } from '@dynamicforms/vue-forms';\nimport { isBoolean, isEmpty, isObjectLike, isPlainObject, isString } from 'lodash-es';\nimport { type MaybeRefOrGetter, toValue } from 'vue';\n\nimport {\n type ActionDisplayStyle,\n actionDisplayStyles,\n defaultDisplayStyle,\n isActionDisplayStyle,\n} from './action-display-style';\nimport { BreakpointNames, BreakpointsJSON, ResponsiveRenderOptions } from './responsive-render-options';\n\nexport interface ActionRenderOptions extends ActionValue {\n /** The text of the action, rendered when {@link showLabel} is set and the text is not empty. `ActionValue`\n * types this `unknown`, leaving what a label is to the rendering library; here it is a string, a ref to one or a\n * function returning one. A ref or a function is read while the action renders, so a label that follows the\n * locale is `() => t('Save')`. */\n label?: MaybeRefOrGetter<string>;\n /** The icon of the action, a name `vue-cached-icon` resolves, rendered when {@link showIcon} is set and the\n * name is not empty. Typed here for the same reason `label` is. */\n icon?: string;\n /** Unique identifier for the action. Purely informational to `<df-actions>` itself - it is not used for\n * rendering - but by convention should match the key under which the action is registered in a\n * `FormActions` (`Record<string, Action>`) map passed to `@dynamicforms/vuetify-modal-form-kit`'s\n * `modal.message()`/`modal.yesNo()`/etc. That map key (or the action's `fieldName`, when it's part of a\n * `Form.Group`) - not this `name` field - is what the modal's promise actually resolves with; keeping them\n * in sync is what lets callers do e.g. `if (await modal.yesNo(...) === 'yes')`. */\n name?: string;\n /** How the action is rendered: `'button'` for a tonal `<v-btn>`, or `'text'` for a text-variant `<v-btn>`. */\n renderAs?: ActionDisplayStyle;\n /** Whether the label is shown. If `label` is empty, the label is never shown regardless of this flag. */\n showLabel?: boolean;\n /** Whether the icon is shown. If `icon` is empty, the icon is never shown regardless of this flag. */\n showIcon?: boolean;\n /** Marks this as the action to trigger on Enter when rendered inside `<df-modal>` (see that component's\n * `onKeydown` in `@dynamicforms/vuetify-modal-form-kit`) - e.g. a \"Save\" or \"Yes\" action. In `<df-actions>` it\n * also colors the button `primary`, unless overridden via `passthroughAttrs.color`. At most one action in a\n * given set should set this. */\n defaultConfirm?: boolean;\n /** Marks this as the action to trigger on Escape when rendered inside `<df-modal>` (see that component's\n * `onKeydown` in `@dynamicforms/vuetify-modal-form-kit`) - e.g. a \"Cancel\" or \"No\" action. In `<df-actions>` it\n * also colors the button `secondary`, unless overridden via `passthroughAttrs.color`. At most one action in a\n * given set should set this (an action such as `Action.closeAction()` may set both `defaultConfirm` and\n * `defaultReject` so it fires on either key). */\n defaultReject?: boolean;\n /** Additional props/attrs forwarded verbatim to the rendered `<v-btn>` (e.g. `color`, `loading`, `density`,\n * `rounded`, `block`, `prependIcon`, ...), taking precedence over `<df-actions>`'s own computed bindings\n * (`variant`, `color`, `disabled`). Mirrors the `passthroughAttrs` convention used by `df-input`/`df-file`/etc\n * (see `helpers/input-base.ts`); it has to live on the action's value here because `<df-actions>` renders a\n * whole array of buttons, not just one. */\n passthroughAttrs?: Record<string, any>;\n}\n/**\n * What one breakpoint of an action's value may state: the members that describe how the action is drawn.\n * `name`, `defaultConfirm` and `defaultReject` are not among them - which key a modal resolves with, and which\n * key fires the action, are properties of the action itself and do not depend on the width of the screen.\n */\nexport type ActionBreakpointRenderOptions = Omit<ActionRenderOptions, 'name' | 'defaultConfirm' | 'defaultReject'>;\nexport type ActionBreakpointOptions = BreakpointsJSON<ActionRenderOptions, ActionBreakpointRenderOptions>;\n\nexport class ResponsiveActionRenderOptions extends ResponsiveRenderOptions<ActionRenderOptions> {\n protected cleanBreakpoint(bp?: ActionRenderOptions, defaultIfEmpty: boolean = false): ActionRenderOptions | null {\n if ((!bp || !isObjectLike(bp)) && !defaultIfEmpty) return null;\n\n const result: ActionRenderOptions = {};\n if (defaultIfEmpty) {\n result.renderAs = defaultDisplayStyle;\n result.showLabel = true;\n result.showIcon = true;\n }\n\n if (bp) {\n if (bp.renderAs != null) {\n // a style nobody defined is refused rather than drawn as the default\n if (!isActionDisplayStyle(bp.renderAs)) {\n throw new Error(`'${bp.renderAs}' is not an action display style: ${actionDisplayStyles.join(', ')}`);\n }\n result.renderAs = bp.renderAs;\n }\n const label = toValue(bp.label);\n if (isString(label)) result.label = label;\n if (isString(bp.icon)) result.icon = bp.icon;\n if (isBoolean(bp.showLabel)) result.showLabel = bp.showLabel;\n if (isBoolean(bp.showIcon)) result.showIcon = bp.showIcon;\n if (isString(bp.name)) result.name = bp.name;\n if (isBoolean(bp.defaultConfirm)) result.defaultConfirm = bp.defaultConfirm;\n if (isBoolean(bp.defaultReject)) result.defaultReject = bp.defaultReject;\n // copied rather than kept by identity, so the cascade's shallow merge of a later breakpoint's attrs does\n // not write into the object the action holds\n if (isPlainObject(bp.passthroughAttrs)) result.passthroughAttrs = { ...bp.passthroughAttrs };\n }\n\n return Object.keys(result).length ? result : null;\n }\n}\n\n/** `ActionRenderOptions` with the label read: a string. */\nexport type ResolvedActionRenderOptions = Omit<ActionRenderOptions, 'label'> & { label?: string };\n\n/**\n * What one action renders as at `breakpoint`, read off the value of any `Action`. The members\n * `ActionRenderOptions` adds over `ActionValue` are taken where the value carries them and defaulted where it does\n * not, so an action holding nothing but a label - which is all a `@dynamicforms/vue-forms` `Action` declares -\n * renders as a button showing that label.\n *\n * `label` and `icon` come back only where the matching flag says they are shown, and the flags come back false\n * where there is no text or name to show, so a caller renders each member on its own flag and never on emptiness.\n */\nexport function getRenderOptionsForBreakpoint(\n value: ActionValue,\n breakpoint: BreakpointNames,\n): ResolvedActionRenderOptions {\n const options = new ResponsiveActionRenderOptions(value as ActionBreakpointOptions);\n const partial = options.getOptionsForBreakpoint(breakpoint);\n // cleanBreakpoint stored the label read\n const label = partial.label as string | undefined;\n return {\n name: partial.name,\n label: partial.showLabel ? label : undefined,\n icon: partial.showIcon ? partial.icon : undefined,\n renderAs: partial.renderAs,\n showLabel: isString(label) && !isEmpty(label) ? partial.showLabel : false,\n showIcon: isString(partial.icon) && !isEmpty(partial.icon) ? partial.showIcon : false,\n defaultConfirm: partial.defaultConfirm,\n defaultReject: partial.defaultReject,\n passthroughAttrs: partial.passthroughAttrs,\n };\n}\n","import { Action as FormAction, IFieldConstructorParams } from '@dynamicforms/vue-forms';\nimport { isEmpty, isString } from 'lodash-es';\nimport { computed, Ref, toValue } from 'vue';\n\nimport { translate } from '../translations';\n\nimport { ActionBreakpointOptions, getRenderOptionsForBreakpoint } from './action-render-options';\nimport { BreakpointNames } from './responsive-render-options';\n\nclass Action extends FormAction<ActionBreakpointOptions> {\n /** @see getRenderOptionsForBreakpoint, which answers the same for the value of any `Action` */\n getBreakpointValue(breakpoint: Ref<BreakpointNames>) {\n return computed(() => getRenderOptionsForBreakpoint(this.value, breakpoint.value));\n }\n\n /** The label read: where the value holds a ref or a function, the string it gives now. */\n get label(): string | undefined {\n return toValue(this.value.label);\n }\n\n set label(newValue: ActionBreakpointOptions['label']) {\n super.label = newValue;\n }\n\n /** @see ActionRenderOptions.name */\n get name() {\n return this.value.name;\n }\n\n /**\n * The label as this action renders it: the text where {@link ActionRenderOptions.showLabel} states it is shown,\n * and `undefined` where it is not. `label` is the base class's, and answers the text whatever the flag says.\n */\n get renderedLabel(): string | undefined {\n return this.value.showLabel ? toValue(this.value.label) : undefined;\n }\n\n /** @see ActionRenderOptions.showLabel */\n get showLabel() {\n const label = toValue(this.value.label);\n return isString(label) && !isEmpty(label) ? this.value.showLabel : false;\n }\n\n /**\n * The icon as this action renders it: the name where {@link ActionRenderOptions.showIcon} states it is shown,\n * and `undefined` where it is not. `icon` is the base class's, and answers the name whatever the flag says.\n */\n get renderedIcon() {\n return this.value.showIcon ? this.value.icon : undefined;\n }\n\n /** @see ActionRenderOptions.showIcon */\n get showIcon() {\n return isString(this.value.icon) && !isEmpty(this.value.icon) ? this.value.showIcon : false;\n }\n\n /** @see ActionRenderOptions.renderAs */\n get renderAs() {\n return this.value.renderAs;\n }\n\n /** @see ActionRenderOptions.passthroughAttrs */\n get passthroughAttrs() {\n return this.value.passthroughAttrs;\n }\n\n static closeAction(data?: Partial<IFieldConstructorParams<ActionBreakpointOptions>>) {\n const init: Partial<IFieldConstructorParams<ActionBreakpointOptions>> = {\n ...(data ?? {}), // any properties in data should overwrite properties in the constant\n value: {\n name: 'close',\n label: () => translate('Close'),\n icon: 'ion-close-outline',\n renderAs: 'button',\n showLabel: true,\n showIcon: true,\n },\n };\n init.value = { ...init.value, ...(data?.value ?? {}) }; // data may only contain partial info of the value\n return new Action(init);\n }\n\n static yesAction(data?: Partial<IFieldConstructorParams<ActionBreakpointOptions>>) {\n const init: Partial<IFieldConstructorParams<ActionBreakpointOptions>> = {\n ...(data ?? {}), // any properties in data should overwrite properties in the constant\n value: {\n name: 'yes',\n label: () => translate('Yes'),\n icon: 'ion-thumbs-up-outline',\n renderAs: 'button',\n showLabel: true,\n showIcon: true,\n },\n };\n init.value = { ...init.value, ...(data?.value ?? {}) }; // data may only contain partial info of the value\n return new Action(init);\n }\n\n static noAction(data?: Partial<IFieldConstructorParams<ActionBreakpointOptions>>) {\n const init: Partial<IFieldConstructorParams<ActionBreakpointOptions>> = {\n ...(data ?? {}), // any properties in data should overwrite properties in the constant\n value: {\n name: 'no',\n label: () => translate('No'),\n icon: 'ion-thumbs-down-outline',\n renderAs: 'button',\n showLabel: true,\n showIcon: true,\n },\n };\n init.value = { ...init.value, ...(data?.value ?? {}) }; // data may only contain partial info of the value\n return new Action(init);\n }\n}\n\nexport { Action };\n","import Form, { ValidationError } from '@dynamicforms/vue-forms';\nimport { inject, onBeforeUnmount, ref, watch, type Ref } from 'vue';\n\nimport { FileComms, FileGoneError } from './df-file.interface';\nimport { VuetifyInputsSettings, vuetifyInputsSettingsKey } from './settings';\n\n/**\n * Runs the `comms.touch` keep-alive interval for `<df-file>`/`<df-image>` while `value` holds a file\n * identifier: starts it once `value` becomes truthy, stops it once it doesn't, and stops it on unmount.\n * `onGone` is called with `err.errorText` whenever a touch rejects with a {@link FileGoneError}; any other\n * rejection is left unhandled beyond that (it's a transient failure, for the consumer to act on if at all).\n */\nexport function useFileTouchKeepAlive(\n value: Ref<string | null>,\n comms: () => FileComms,\n touchIntervalProp: () => number | undefined,\n onGone: (errorText: string) => void,\n) {\n const settings = inject<VuetifyInputsSettings>(vuetifyInputsSettingsKey, {});\n const touchIntervalHandle = ref<number | null>(null);\n\n function clearTouchInterval() {\n if (touchIntervalHandle.value) window.clearInterval(touchIntervalHandle.value);\n }\n\n function setupTouchInterval() {\n clearTouchInterval();\n const interval = touchIntervalProp() ?? settings.defaultTouchInterval ?? 60_000;\n touchIntervalHandle.value = window.setInterval(() => {\n if (value.value) {\n comms()\n .touch(value.value)\n .catch((err) => {\n if (err instanceof FileGoneError) onGone(err.errorText);\n });\n }\n }, interval);\n }\n\n onBeforeUnmount(() => clearTouchInterval());\n watch(value, (newValue) => (newValue ? setupTouchInterval() : clearTouchInterval()));\n\n return { setupTouchInterval, clearTouchInterval };\n}\n\n/**\n * Reports a {@link FileGoneError}'s message on `control`, where one is bound. Kept outside the component's own\n * script so the write to `control.errors` isn't seen as a `.vue` component mutating its own prop — the write\n * goes through `Form.FieldBase`'s own setter, the same way `useInputBase`'s `touched` does.\n */\nexport function setFileGoneError(control: Form.FieldBase | undefined, errorText: string) {\n if (control) control.errors = [new ValidationError('file_gone', {}, errorText, 'server')];\n}\n","<template>\n <div\n v-if=\"actionsRef.length > 0\"\n class=\"text-end df-actions\"\n :class=\"{\n 'button-group': showAsGroup === 'grouped' || showAsGroup === 'grouped-no-borders',\n 'with-border': showAsGroup === 'grouped',\n }\"\n >\n <v-btn\n v-for=\"(action, idx) in actionsWithBreakpoint\"\n :key=\"idx\"\n :variant=\"action.renderAs === 'button' ? 'tonal' : 'text'\"\n :color=\"defaultActionColor(action)\"\n :disabled=\"!action.action.effectiveEnabled || action.action.busy\"\n :loading=\"action.action.busy\"\n :elevation=\"0\"\n :size=\"buttonSize\"\n :density=\"buttonDensity\"\n :class=\"{\n 'd-none': action.action.visibility === 'hidden',\n invisible: action.action.visibility === 'invisible',\n }\"\n v-bind=\"action.passthroughAttrs\"\n @click.stop=\"(event: MouseEvent) => action.action.execute(event)\"\n >\n <cached-icon v-if=\"action.icon\" :name=\"action.icon\" />\n <span v-if=\"action.icon && action.label\" style=\"width: 0.5rem\" />\n <span v-if=\"action.label\">{{ action.label }}</span>\n </v-btn>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, unref } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfActionsProps } from './dynamicforms-component-props';\nimport { ActionRenderOptions, getRenderOptionsForBreakpoint, useBreakpoint } from './helpers';\n\nconst props = withDefaults(defineProps<DfActionsProps>(), {\n buttonSize: 'default',\n buttonDensity: 'default',\n showAsGroup: 'no',\n});\n\nconst breakpoint = useBreakpoint();\nconst actionsRef = computed(() => unref(props.actions).filter((action) => action.visibility !== 'suppress'));\n// What each button draws is read off the action's value rather than through the accessors this library's `Action`\n// adds over it, so an action declared as a `@dynamicforms/vue-forms` one - which declares none of them - is drawn\n// as well. The spread is that value resolved at the current breakpoint.\nconst actionsWithBreakpoint = computed(() =>\n actionsRef.value.map((action) => ({\n action,\n ...getRenderOptionsForBreakpoint(action.value, breakpoint.value),\n })),\n);\n\nfunction defaultActionColor(options: ActionRenderOptions): string | undefined {\n if (options.defaultConfirm) return 'primary';\n if (options.defaultReject) return 'secondary';\n return undefined;\n}\n</script>\n\n<style>\n.df-actions.button-group {\n border-radius: 0.5em;\n /* the following two make the container fit the small buttons. without them there would be a top margin */\n line-height: 0;\n height: fit-content;\n}\n.df-actions.button-group .v-btn {\n border: none;\n border-radius: 0;\n margin: 0 !important;\n padding: 0 0.25em;\n}\n.df-actions.button-group .v-btn:first-child {\n border-start-start-radius: 0.5em;\n border-end-start-radius: 0.5em;\n}\n.df-actions.button-group .v-btn:last-child {\n border-start-end-radius: 0.5em;\n border-end-end-radius: 0.5em;\n}\n.df-actions.button-group.with-border {\n border: 0.1em solid currentColor;\n}\n.df-actions.button-group.with-border .v-btn:not(:first-child) {\n border-inline-start: 0.1em solid currentColor;\n}\n.df-actions .v-btn:not(:first-child) {\n margin-left: 0.5em;\n}\n</style>\n","<template>\n <div\n v-if=\"actionsRef.length > 0\"\n class=\"text-end df-actions\"\n :class=\"{\n 'button-group': showAsGroup === 'grouped' || showAsGroup === 'grouped-no-borders',\n 'with-border': showAsGroup === 'grouped',\n }\"\n >\n <v-btn\n v-for=\"(action, idx) in actionsWithBreakpoint\"\n :key=\"idx\"\n :variant=\"action.renderAs === 'button' ? 'tonal' : 'text'\"\n :color=\"defaultActionColor(action)\"\n :disabled=\"!action.action.effectiveEnabled || action.action.busy\"\n :loading=\"action.action.busy\"\n :elevation=\"0\"\n :size=\"buttonSize\"\n :density=\"buttonDensity\"\n :class=\"{\n 'd-none': action.action.visibility === 'hidden',\n invisible: action.action.visibility === 'invisible',\n }\"\n v-bind=\"action.passthroughAttrs\"\n @click.stop=\"(event: MouseEvent) => action.action.execute(event)\"\n >\n <cached-icon v-if=\"action.icon\" :name=\"action.icon\" />\n <span v-if=\"action.icon && action.label\" style=\"width: 0.5rem\" />\n <span v-if=\"action.label\">{{ action.label }}</span>\n </v-btn>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, unref } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfActionsProps } from './dynamicforms-component-props';\nimport { ActionRenderOptions, getRenderOptionsForBreakpoint, useBreakpoint } from './helpers';\n\nconst props = withDefaults(defineProps<DfActionsProps>(), {\n buttonSize: 'default',\n buttonDensity: 'default',\n showAsGroup: 'no',\n});\n\nconst breakpoint = useBreakpoint();\nconst actionsRef = computed(() => unref(props.actions).filter((action) => action.visibility !== 'suppress'));\n// What each button draws is read off the action's value rather than through the accessors this library's `Action`\n// adds over it, so an action declared as a `@dynamicforms/vue-forms` one - which declares none of them - is drawn\n// as well. The spread is that value resolved at the current breakpoint.\nconst actionsWithBreakpoint = computed(() =>\n actionsRef.value.map((action) => ({\n action,\n ...getRenderOptionsForBreakpoint(action.value, breakpoint.value),\n })),\n);\n\nfunction defaultActionColor(options: ActionRenderOptions): string | undefined {\n if (options.defaultConfirm) return 'primary';\n if (options.defaultReject) return 'secondary';\n return undefined;\n}\n</script>\n\n<style>\n.df-actions.button-group {\n border-radius: 0.5em;\n /* the following two make the container fit the small buttons. without them there would be a top margin */\n line-height: 0;\n height: fit-content;\n}\n.df-actions.button-group .v-btn {\n border: none;\n border-radius: 0;\n margin: 0 !important;\n padding: 0 0.25em;\n}\n.df-actions.button-group .v-btn:first-child {\n border-start-start-radius: 0.5em;\n border-end-start-radius: 0.5em;\n}\n.df-actions.button-group .v-btn:last-child {\n border-start-end-radius: 0.5em;\n border-end-end-radius: 0.5em;\n}\n.df-actions.button-group.with-border {\n border: 0.1em solid currentColor;\n}\n.df-actions.button-group.with-border .v-btn:not(:first-child) {\n border-inline-start: 0.1em solid currentColor;\n}\n.df-actions .v-btn:not(:first-child) {\n margin-left: 0.5em;\n}\n</style>\n","<template>\n <v-checkbox\n v-if=\"isRendered\"\n v-model=\"boolValue\"\n density=\"compact\"\n :class=\"[densityClass, visibilityClass]\"\n :indeterminate=\"indeterminate\"\n :false-value=\"false\"\n :true-value=\"true\"\n v-bind=\"vuetifyBindings as any\"\n @change=\"change\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :allow-wrap=\"true\" :data=\"labelData as any\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n </v-checkbox>\n</template>\n\n<script setup lang=\"ts\">\nimport { clone } from 'lodash-es';\nimport { computed } from 'vue';\n\nimport { DfCheckboxProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfCheckboxProps>(), { ...defaultBaseProps, allowNull: false });\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, shownErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\n\nconst indeterminate = computed(() => props.allowNull && value.value == null);\n\nconst boolValue = computed({\n get(): any {\n return value.value;\n },\n set() {},\n});\n\nfunction change() {\n const oldVal = clone(value.value);\n if (oldVal === true) {\n value.value = props.allowNull ? null : false;\n } else {\n value.value = oldVal === false;\n }\n}\n</script>\n","<template>\n <v-checkbox\n v-if=\"isRendered\"\n v-model=\"boolValue\"\n density=\"compact\"\n :class=\"[densityClass, visibilityClass]\"\n :indeterminate=\"indeterminate\"\n :false-value=\"false\"\n :true-value=\"true\"\n v-bind=\"vuetifyBindings as any\"\n @change=\"change\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :allow-wrap=\"true\" :data=\"labelData as any\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n </v-checkbox>\n</template>\n\n<script setup lang=\"ts\">\nimport { clone } from 'lodash-es';\nimport { computed } from 'vue';\n\nimport { DfCheckboxProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfCheckboxProps>(), { ...defaultBaseProps, allowNull: false });\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, shownErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\n\nconst indeterminate = computed(() => props.allowNull && value.value == null);\n\nconst boolValue = computed({\n get(): any {\n return value.value;\n },\n set() {},\n});\n\nfunction change() {\n const oldVal = clone(value.value);\n if (oldVal === true) {\n value.value = props.allowNull ? null : false;\n } else {\n value.value = oldVal === false;\n }\n}\n</script>\n","import { onMounted, type Ref, shallowRef } from 'vue';\nimport { useDisplay } from 'vuetify';\n\n/**\n * Whether a part of a component that renders only in the browser is rendered now: a menu, a picker, an autocomplete.\n *\n * - On the server: `false`.\n * - In the browser, where Vuetify is created with `ssr: true`: `false` until the component is mounted, so the first\n * render matches the server's and hydrates, then `true`.\n * - In the browser otherwise: `true` from the start.\n *\n * Vuetify's menus are not rendered on the server: each one rendered there stays in memory after the request.\n */\nexport function useClientRendered(): Ref<boolean> {\n if (typeof window === 'undefined') return shallowRef(false);\n if (!useDisplay().ssr) return shallowRef(true);\n const rendered = shallowRef(false);\n onMounted(() => {\n rendered.value = true;\n });\n return rendered;\n}\n","<template>\n <v-btn variant=\"text\" :text=\"translate('Cancel')\" @click=\"cancel\" />\n <v-btn variant=\"text\" :disabled=\"isPristine\" :text=\"translate('Ok')\" @click=\"save\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { translate } from './translations';\n\n/**\n * The Cancel and OK of a `v-confirm-edit`, from its default slot's `save`, `cancel` and `isPristine`. Cancel is\n * enabled while nothing has changed, so it closes the picker; `v-confirm-edit`'s own actions disable both until a\n * change. The labels are the library's strings `Cancel` and `Ok`.\n */\ndefineProps<{ save: () => void; cancel: () => void; isPristine: boolean }>();\n</script>\n","<template>\n <v-btn variant=\"text\" :text=\"translate('Cancel')\" @click=\"cancel\" />\n <v-btn variant=\"text\" :disabled=\"isPristine\" :text=\"translate('Ok')\" @click=\"save\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { translate } from './translations';\n\n/**\n * The Cancel and OK of a `v-confirm-edit`, from its default slot's `save`, `cancel` and `isPristine`. Cancel is\n * enabled while nothing has changed, so it closes the picker; `v-confirm-edit`'s own actions disable both until a\n * change. The labels are the library's strings `Cancel` and `Ok`.\n */\ndefineProps<{ save: () => void; cancel: () => void; isPristine: boolean }>();\n</script>\n","/**\n * The time after a picker changes its view during which a double-click does not confirm. It is longer than the\n * double-click interval of common systems (500 ms on Windows, less on macOS and GNOME), so where the first click of a\n * double-click changes the view - an hour switching the clock to the minutes, a month switching to its days, a day of\n * an adjacent month switching the calendar to that month - the second click, which lands on a choice the user did not\n * aim at, does not confirm it.\n */\nexport const viewSettleMs = 600;\n\n/**\n * Double-click confirmation for a picker inside `v-confirm-edit`: a double-click on a choice selects it and confirms\n * it, as a choice followed by OK does. `viewChanged` is bound to the picker's events that change what it shows:\n * `update:viewMode`, and `update:month` and `update:year` of a date picker.\n */\nexport function usePickerDoubleClick() {\n let viewChangedAt = Number.NEGATIVE_INFINITY;\n\n return {\n viewChanged(): void {\n viewChangedAt = Date.now();\n },\n /** Calls `save` for a double-click on an element matching `selector`, unless the view changed just before. */\n saveOnDoubleClick(event: MouseEvent, selector: string, save: () => void): void {\n if (Date.now() - viewChangedAt < viewSettleMs) return;\n if (event.target instanceof Element && event.target.closest(selector)) save();\n },\n };\n}\n","<template>\n <v-text-field\n v-if=\"isRendered\"\n v-model=\"value\"\n :class=\"[densityClass, visibilityClass]\"\n :clearable=\"allowNull\"\n type=\"text\"\n v-bind=\"vuetifyBindings\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n <template #prepend-inner>\n <div\n style=\"width: 24px; height: 24px; border-radius: 4px; border: 1px solid #ccc\"\n :style=\"{ backgroundColor: value }\"\n />\n </template>\n <template #default>\n <v-menu v-if=\"clientRendered\" v-model=\"dropdownShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-confirm-edit v-model=\"value\" hide-actions @cancel=\"dropdownShown = false\" @save=\"concludeEdit\">\n <template #default=\"{ model: proxyModel, save, cancel, isPristine }\">\n <v-card>\n <v-color-picker\n v-model=\"proxyModel.value\"\n mode=\"hexa\"\n @dblclick=\"saveOnDoubleClick($event, colorChoices, save)\"\n />\n <v-card-actions class=\"justify-end\">\n <confirm-actions :save=\"save\" :cancel=\"cancel\" :is-pristine=\"isPristine\" />\n </v-card-actions>\n </v-card>\n </template>\n </v-confirm-edit>\n </v-menu>\n </template>\n </v-text-field>\n</template>\n\n<script setup lang=\"ts\">\nimport { ValidationError } from '@dynamicforms/vue-forms';\nimport { ref } from 'vue';\n\nimport { DfColorProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\nimport { useClientRendered } from './helpers/client-rendered';\nimport ConfirmActions from './helpers/confirm-actions.vue';\nimport { usePickerDoubleClick } from './helpers/picker-double-click';\n\nconst props = withDefaults(defineProps<DfColorProps>(), { ...defaultBaseProps, allowNull: false });\n\ninterface Emits extends BaseEmits {}\n\nconst emits = defineEmits<Emits>();\n\nconst hexColor = /^#?([a-fA-F0-9]{3}|[a-fA-F0-9]{4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/;\n\n// without a control the component checks the format itself; a bound control is checked by its own validators\nfunction hexColorErrors(): ValidationError[] {\n const val = value.value;\n if (!val && props.allowNull) return [];\n if (hexColor.test(val ?? '')) return [];\n return [new ValidationError('invalid_hex_color', {}, 'Not a valid hex string.', 'validator')];\n}\n\nconst { densityClass, isRendered, label, shownErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n hexColorErrors,\n);\nconst dropdownShown = ref(false);\nconst clientRendered = useClientRendered();\nconst colorChoices = '.v-color-picker-canvas';\nconst { saveOnDoubleClick } = usePickerDoubleClick();\n\n// a value confirmed in the picker concludes the edit: the field may hold no focus to lose\nfunction concludeEdit() {\n dropdownShown.value = false;\n touched.value = true;\n}\n</script>\n","<template>\n <v-text-field\n v-if=\"isRendered\"\n v-model=\"value\"\n :class=\"[densityClass, visibilityClass]\"\n :clearable=\"allowNull\"\n type=\"text\"\n v-bind=\"vuetifyBindings\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n <template #prepend-inner>\n <div\n style=\"width: 24px; height: 24px; border-radius: 4px; border: 1px solid #ccc\"\n :style=\"{ backgroundColor: value }\"\n />\n </template>\n <template #default>\n <v-menu v-if=\"clientRendered\" v-model=\"dropdownShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-confirm-edit v-model=\"value\" hide-actions @cancel=\"dropdownShown = false\" @save=\"concludeEdit\">\n <template #default=\"{ model: proxyModel, save, cancel, isPristine }\">\n <v-card>\n <v-color-picker\n v-model=\"proxyModel.value\"\n mode=\"hexa\"\n @dblclick=\"saveOnDoubleClick($event, colorChoices, save)\"\n />\n <v-card-actions class=\"justify-end\">\n <confirm-actions :save=\"save\" :cancel=\"cancel\" :is-pristine=\"isPristine\" />\n </v-card-actions>\n </v-card>\n </template>\n </v-confirm-edit>\n </v-menu>\n </template>\n </v-text-field>\n</template>\n\n<script setup lang=\"ts\">\nimport { ValidationError } from '@dynamicforms/vue-forms';\nimport { ref } from 'vue';\n\nimport { DfColorProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\nimport { useClientRendered } from './helpers/client-rendered';\nimport ConfirmActions from './helpers/confirm-actions.vue';\nimport { usePickerDoubleClick } from './helpers/picker-double-click';\n\nconst props = withDefaults(defineProps<DfColorProps>(), { ...defaultBaseProps, allowNull: false });\n\ninterface Emits extends BaseEmits {}\n\nconst emits = defineEmits<Emits>();\n\nconst hexColor = /^#?([a-fA-F0-9]{3}|[a-fA-F0-9]{4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/;\n\n// without a control the component checks the format itself; a bound control is checked by its own validators\nfunction hexColorErrors(): ValidationError[] {\n const val = value.value;\n if (!val && props.allowNull) return [];\n if (hexColor.test(val ?? '')) return [];\n return [new ValidationError('invalid_hex_color', {}, 'Not a valid hex string.', 'validator')];\n}\n\nconst { densityClass, isRendered, label, shownErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n hexColorErrors,\n);\nconst dropdownShown = ref(false);\nconst clientRendered = useClientRendered();\nconst colorChoices = '.v-color-picker-canvas';\nconst { saveOnDoubleClick } = usePickerDoubleClick();\n\n// a value confirmed in the picker concludes the edit: the field may hold no focus to lose\nfunction concludeEdit() {\n dropdownShown.value = false;\n touched.value = true;\n}\n</script>\n","<template>\n <input-base v-bind=\"props\" :class=\"densityClass\" :clearable=\"clearable\" @click:clear=\"clear\" @blur=\"touched = true\">\n <template #default=\"slotProps\">\n <div\n :class=\"[\n 'd-flex',\n 'w-100',\n ['plain', 'underlined'].includes(vuetifyBindings.variant) ? undefined : 'ml-4',\n 'df-input-wrapper',\n density,\n ]\"\n >\n <v-text-field\n v-if=\"['date', 'datetime'].includes(inputType)\"\n v-model=\"dateFormatted\"\n style=\"flex-grow: 4\"\n density=\"compact\"\n variant=\"plain\"\n :clearable=\"false\"\n :hide-details=\"true\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"`${vuetifyBindings.name}-date`\"\n :placeholder=\"vuetifyBindings.placeholder\"\n v-bind=\"passthroughAttrs\"\n @click=\"dropdown = 'date'\"\n @keydown.space=\"dropdown = 'date'\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template #default>\n <v-menu v-if=\"clientRendered\" v-model=\"dateMenuShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-confirm-edit v-model=\"valueAsDate\" hide-actions @cancel=\"dropdown = ''\" @save=\"concludeEdit\">\n <template #default=\"{ model: proxyModel, save, cancel, isPristine }\">\n <v-date-picker\n v-model=\"proxyModel.value\"\n :hide-header=\"true\"\n :first-day-of-week=\"firstDayOfWeek\"\n :show-adjacent-months=\"true\"\n :show-week=\"true\"\n @update:view-mode=\"viewChanged\"\n @update:month=\"viewChanged\"\n @update:year=\"viewChanged\"\n @dblclick=\"saveOnDoubleClick($event, '.v-date-picker-month__day', save)\"\n >\n <template #actions>\n <confirm-actions :save=\"save\" :cancel=\"cancel\" :is-pristine=\"isPristine\" />\n </template>\n </v-date-picker>\n </template>\n </v-confirm-edit>\n </v-menu>\n </template>\n </v-text-field>\n\n <v-text-field\n v-if=\"['time', 'datetime'].includes(inputType)\"\n v-model=\"timeFormatted\"\n style=\"flex-grow: 3\"\n density=\"compact\"\n variant=\"plain\"\n :clearable=\"false\"\n :hide-details=\"true\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"`${vuetifyBindings.name}-time`\"\n :placeholder=\"inputType === 'time' ? vuetifyBindings.placeholder : undefined\"\n v-bind=\"passthroughAttrs\"\n @click=\"dropdown = 'time'\"\n @keydown.space=\"dropdown = 'time'\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template #default>\n <v-menu v-if=\"clientRendered\" v-model=\"timeMenuShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-confirm-edit v-model=\"valueAsTimeString\" hide-actions @cancel=\"dropdown = ''\" @save=\"concludeEdit\">\n <template #default=\"{ model: proxyModel, save, cancel, isPristine }\">\n <v-time-picker\n v-model=\"proxyModel.value\"\n :hide-header=\"true\"\n format=\"24hr\"\n @update:view-mode=\"viewChanged\"\n @dblclick=\"saveOnDoubleClick($event, '.v-time-picker-clock', save)\"\n >\n <template #actions>\n <confirm-actions :save=\"save\" :cancel=\"cancel\" :is-pristine=\"isPristine\" />\n </template>\n </v-time-picker>\n </template>\n </v-confirm-edit>\n </v-menu>\n </template>\n </v-text-field>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { format, parse, parseISO } from 'date-fns';\nimport { toNumber, isNaN } from 'lodash-es';\nimport { ref, computed, inject, watch, toRefs, unref } from 'vue';\n\nimport { DfDateTimeProps } from './dynamicforms-component-props';\nimport {\n BaseEmits,\n DateTimeLocaleConfig,\n defaultBaseProps,\n InputBase,\n useInputBase,\n type VuetifyInputsSettings,\n vuetifyInputsSettingsKey,\n} from './helpers';\nimport { useClientRendered } from './helpers/client-rendered';\nimport ConfirmActions from './helpers/confirm-actions.vue';\nimport { usePickerDoubleClick } from './helpers/picker-double-click';\n\nconst props = withDefaults(defineProps<DfDateTimeProps>(), {\n ...defaultBaseProps,\n inputType: 'datetime',\n displayFormatDate: 'P',\n displayFormatTime: 'p',\n});\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst settings = inject<VuetifyInputsSettings>(vuetifyInputsSettingsKey, {});\nconst currentLocale = computed(\n () => props.locale ?? unref(settings.dateTimeLocale) ?? unref(DateTimeLocaleConfig.dateTimeLocale),\n);\nconst firstDayOfWeek = computed(() => currentLocale.value.options?.weekStartsOn ?? 1);\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase<string | null>(props, emits);\nconst { inputType, displayFormatDate, displayFormatTime } = toRefs(props);\n\nconst dropdown = ref('');\nconst clientRendered = useClientRendered();\nconst dateMenuShown = computed({\n get() {\n return unref(dropdown) === 'date';\n },\n set(newValue: boolean) {\n dropdown.value = newValue ? 'date' : '';\n },\n});\nconst timeMenuShown = computed({\n get() {\n return unref(dropdown) === 'time';\n },\n set(newValue: boolean) {\n dropdown.value = newValue ? 'time' : '';\n },\n});\n\n// a value picked in the menu or cleared concludes the edit: the field may hold no focus to lose\nfunction concludeEdit() {\n dropdown.value = '';\n touched.value = true;\n}\n\nconst { viewChanged, saveOnDoubleClick } = usePickerDoubleClick();\n\nfunction clear() {\n value.value = null;\n touched.value = true;\n}\n\nconst formatNaive = (val: Date) => `${format(val, 'yyyy-MM-dd')}T${format(val, 'HH:mm')}:00`;\n\nconst valueISOFull = ref<string | null>(null);\n// the date and time parts of `base` with one of them replaced by the same part of `newISOValue`\nfunction mergeParts(base: string, newISOValue: string, dateOrTimeIdx: number) {\n const vif = base.split(/[TZ]/g);\n vif[dateOrTimeIdx] = newISOValue.split(/[TZ]/g)[dateOrTimeIdx];\n return vif;\n}\n\nconst naiveFromParts = (vif: string[]) => formatNaive(new Date(`${vif[0]}T${vif[1].split('.')[0]}`));\n\n// Reading the field's value (dateOrTimeIdx -1) only sets what the control shows: the field keeps the string it holds\n// until the user edits the date or the time. parseISO reads a date without a time as local midnight, where the Date\n// constructor reads it as UTC midnight and shows the previous day west of Greenwich.\nfunction setValueISOFull(newISOValue: string | null, dateOrTimeIdx: number) {\n if (newISOValue == null) {\n valueISOFull.value = null;\n } else if (dateOrTimeIdx === -1) {\n if (unref(inputType) === 'time') {\n valueISOFull.value = naiveFromParts(mergeParts(formatNaive(new Date()), `T${newISOValue}`, 1));\n } else {\n valueISOFull.value = formatNaive(parseISO(newISOValue));\n }\n } else {\n const vif = mergeParts(valueISOFull.value ?? formatNaive(new Date()), newISOValue, dateOrTimeIdx);\n valueISOFull.value = naiveFromParts(vif);\n if (unref(inputType) === 'date') value.value = vif[0];\n else if (unref(inputType) === 'time') value.value = vif[1];\n // the offset is the one in force on the date written, not today's: across a DST change the two differ by an hour\n else value.value = valueISOFull.value + format(new Date(valueISOFull.value), 'XXX');\n }\n}\n\nwatch(value, (newValue: string | null) => setValueISOFull(newValue, -1), { immediate: true });\n\nconst valueAsDate = computed({\n get() {\n const uValue = unref(valueISOFull);\n if (uValue == null) return null;\n const res = new Date(uValue);\n return !Number.isNaN(res.getTime()) ? res : null;\n },\n set(newValue: Date) {\n setValueISOFull(formatNaive(newValue), 0);\n },\n});\n\nconst valueAsTimeString = computed({\n get() {\n const val = unref(valueISOFull);\n if (val == null) return '';\n const vif = val.split(/[TZ]/g);\n return vif[1].split('.')[0];\n },\n set(newValue: string) {\n setValueISOFull(`T${newValue}`, 1);\n },\n});\n\nconst dateFormatted = computed({\n get() {\n const vad = unref(valueAsDate);\n if (vad == null) return '';\n return format(vad, unref(displayFormatDate), { locale: currentLocale.value });\n },\n set(newValue: string) {\n try {\n const d = parse(newValue, unref(displayFormatDate), new Date(), { locale: currentLocale.value });\n setValueISOFull(formatNaive(d), 0);\n } catch (err) {\n console.error(err);\n }\n },\n});\n\nconst timeFormatted = computed({\n get() {\n const vad = unref(valueAsDate);\n if (vad == null) return '';\n return format(vad, unref(displayFormatTime), { locale: currentLocale.value });\n },\n set(newValue: string) {\n const d = newValue.match(/(\\d+):(\\d+)\\s?([a-zA-Z]+)?/);\n if (d == null) return;\n let hour = toNumber(d[1]);\n const minute = toNumber(d[2]);\n if (isNaN(hour) || isNaN(minute)) return;\n if (d[3] && d[3].toLowerCase() === 'pm' && hour < 13) hour += 12;\n setValueISOFull(`T${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:00`, 1);\n },\n});\n</script>\n","<template>\n <input-base v-bind=\"props\" :class=\"densityClass\" :clearable=\"clearable\" @click:clear=\"clear\" @blur=\"touched = true\">\n <template #default=\"slotProps\">\n <div\n :class=\"[\n 'd-flex',\n 'w-100',\n ['plain', 'underlined'].includes(vuetifyBindings.variant) ? undefined : 'ml-4',\n 'df-input-wrapper',\n density,\n ]\"\n >\n <v-text-field\n v-if=\"['date', 'datetime'].includes(inputType)\"\n v-model=\"dateFormatted\"\n style=\"flex-grow: 4\"\n density=\"compact\"\n variant=\"plain\"\n :clearable=\"false\"\n :hide-details=\"true\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"`${vuetifyBindings.name}-date`\"\n :placeholder=\"vuetifyBindings.placeholder\"\n v-bind=\"passthroughAttrs\"\n @click=\"dropdown = 'date'\"\n @keydown.space=\"dropdown = 'date'\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template #default>\n <v-menu v-if=\"clientRendered\" v-model=\"dateMenuShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-confirm-edit v-model=\"valueAsDate\" hide-actions @cancel=\"dropdown = ''\" @save=\"concludeEdit\">\n <template #default=\"{ model: proxyModel, save, cancel, isPristine }\">\n <v-date-picker\n v-model=\"proxyModel.value\"\n :hide-header=\"true\"\n :first-day-of-week=\"firstDayOfWeek\"\n :show-adjacent-months=\"true\"\n :show-week=\"true\"\n @update:view-mode=\"viewChanged\"\n @update:month=\"viewChanged\"\n @update:year=\"viewChanged\"\n @dblclick=\"saveOnDoubleClick($event, '.v-date-picker-month__day', save)\"\n >\n <template #actions>\n <confirm-actions :save=\"save\" :cancel=\"cancel\" :is-pristine=\"isPristine\" />\n </template>\n </v-date-picker>\n </template>\n </v-confirm-edit>\n </v-menu>\n </template>\n </v-text-field>\n\n <v-text-field\n v-if=\"['time', 'datetime'].includes(inputType)\"\n v-model=\"timeFormatted\"\n style=\"flex-grow: 3\"\n density=\"compact\"\n variant=\"plain\"\n :clearable=\"false\"\n :hide-details=\"true\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"`${vuetifyBindings.name}-time`\"\n :placeholder=\"inputType === 'time' ? vuetifyBindings.placeholder : undefined\"\n v-bind=\"passthroughAttrs\"\n @click=\"dropdown = 'time'\"\n @keydown.space=\"dropdown = 'time'\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template #default>\n <v-menu v-if=\"clientRendered\" v-model=\"timeMenuShown\" :close-on-content-click=\"false\" activator=\"parent\">\n <v-confirm-edit v-model=\"valueAsTimeString\" hide-actions @cancel=\"dropdown = ''\" @save=\"concludeEdit\">\n <template #default=\"{ model: proxyModel, save, cancel, isPristine }\">\n <v-time-picker\n v-model=\"proxyModel.value\"\n :hide-header=\"true\"\n format=\"24hr\"\n @update:view-mode=\"viewChanged\"\n @dblclick=\"saveOnDoubleClick($event, '.v-time-picker-clock', save)\"\n >\n <template #actions>\n <confirm-actions :save=\"save\" :cancel=\"cancel\" :is-pristine=\"isPristine\" />\n </template>\n </v-time-picker>\n </template>\n </v-confirm-edit>\n </v-menu>\n </template>\n </v-text-field>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { format, parse, parseISO } from 'date-fns';\nimport { toNumber, isNaN } from 'lodash-es';\nimport { ref, computed, inject, watch, toRefs, unref } from 'vue';\n\nimport { DfDateTimeProps } from './dynamicforms-component-props';\nimport {\n BaseEmits,\n DateTimeLocaleConfig,\n defaultBaseProps,\n InputBase,\n useInputBase,\n type VuetifyInputsSettings,\n vuetifyInputsSettingsKey,\n} from './helpers';\nimport { useClientRendered } from './helpers/client-rendered';\nimport ConfirmActions from './helpers/confirm-actions.vue';\nimport { usePickerDoubleClick } from './helpers/picker-double-click';\n\nconst props = withDefaults(defineProps<DfDateTimeProps>(), {\n ...defaultBaseProps,\n inputType: 'datetime',\n displayFormatDate: 'P',\n displayFormatTime: 'p',\n});\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst settings = inject<VuetifyInputsSettings>(vuetifyInputsSettingsKey, {});\nconst currentLocale = computed(\n () => props.locale ?? unref(settings.dateTimeLocale) ?? unref(DateTimeLocaleConfig.dateTimeLocale),\n);\nconst firstDayOfWeek = computed(() => currentLocale.value.options?.weekStartsOn ?? 1);\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase<string | null>(props, emits);\nconst { inputType, displayFormatDate, displayFormatTime } = toRefs(props);\n\nconst dropdown = ref('');\nconst clientRendered = useClientRendered();\nconst dateMenuShown = computed({\n get() {\n return unref(dropdown) === 'date';\n },\n set(newValue: boolean) {\n dropdown.value = newValue ? 'date' : '';\n },\n});\nconst timeMenuShown = computed({\n get() {\n return unref(dropdown) === 'time';\n },\n set(newValue: boolean) {\n dropdown.value = newValue ? 'time' : '';\n },\n});\n\n// a value picked in the menu or cleared concludes the edit: the field may hold no focus to lose\nfunction concludeEdit() {\n dropdown.value = '';\n touched.value = true;\n}\n\nconst { viewChanged, saveOnDoubleClick } = usePickerDoubleClick();\n\nfunction clear() {\n value.value = null;\n touched.value = true;\n}\n\nconst formatNaive = (val: Date) => `${format(val, 'yyyy-MM-dd')}T${format(val, 'HH:mm')}:00`;\n\nconst valueISOFull = ref<string | null>(null);\n// the date and time parts of `base` with one of them replaced by the same part of `newISOValue`\nfunction mergeParts(base: string, newISOValue: string, dateOrTimeIdx: number) {\n const vif = base.split(/[TZ]/g);\n vif[dateOrTimeIdx] = newISOValue.split(/[TZ]/g)[dateOrTimeIdx];\n return vif;\n}\n\nconst naiveFromParts = (vif: string[]) => formatNaive(new Date(`${vif[0]}T${vif[1].split('.')[0]}`));\n\n// Reading the field's value (dateOrTimeIdx -1) only sets what the control shows: the field keeps the string it holds\n// until the user edits the date or the time. parseISO reads a date without a time as local midnight, where the Date\n// constructor reads it as UTC midnight and shows the previous day west of Greenwich.\nfunction setValueISOFull(newISOValue: string | null, dateOrTimeIdx: number) {\n if (newISOValue == null) {\n valueISOFull.value = null;\n } else if (dateOrTimeIdx === -1) {\n if (unref(inputType) === 'time') {\n valueISOFull.value = naiveFromParts(mergeParts(formatNaive(new Date()), `T${newISOValue}`, 1));\n } else {\n valueISOFull.value = formatNaive(parseISO(newISOValue));\n }\n } else {\n const vif = mergeParts(valueISOFull.value ?? formatNaive(new Date()), newISOValue, dateOrTimeIdx);\n valueISOFull.value = naiveFromParts(vif);\n if (unref(inputType) === 'date') value.value = vif[0];\n else if (unref(inputType) === 'time') value.value = vif[1];\n // the offset is the one in force on the date written, not today's: across a DST change the two differ by an hour\n else value.value = valueISOFull.value + format(new Date(valueISOFull.value), 'XXX');\n }\n}\n\nwatch(value, (newValue: string | null) => setValueISOFull(newValue, -1), { immediate: true });\n\nconst valueAsDate = computed({\n get() {\n const uValue = unref(valueISOFull);\n if (uValue == null) return null;\n const res = new Date(uValue);\n return !Number.isNaN(res.getTime()) ? res : null;\n },\n set(newValue: Date) {\n setValueISOFull(formatNaive(newValue), 0);\n },\n});\n\nconst valueAsTimeString = computed({\n get() {\n const val = unref(valueISOFull);\n if (val == null) return '';\n const vif = val.split(/[TZ]/g);\n return vif[1].split('.')[0];\n },\n set(newValue: string) {\n setValueISOFull(`T${newValue}`, 1);\n },\n});\n\nconst dateFormatted = computed({\n get() {\n const vad = unref(valueAsDate);\n if (vad == null) return '';\n return format(vad, unref(displayFormatDate), { locale: currentLocale.value });\n },\n set(newValue: string) {\n try {\n const d = parse(newValue, unref(displayFormatDate), new Date(), { locale: currentLocale.value });\n setValueISOFull(formatNaive(d), 0);\n } catch (err) {\n console.error(err);\n }\n },\n});\n\nconst timeFormatted = computed({\n get() {\n const vad = unref(valueAsDate);\n if (vad == null) return '';\n return format(vad, unref(displayFormatTime), { locale: currentLocale.value });\n },\n set(newValue: string) {\n const d = newValue.match(/(\\d+):(\\d+)\\s?([a-zA-Z]+)?/);\n if (d == null) return;\n let hour = toNumber(d[1]);\n const minute = toNumber(d[2]);\n if (isNaN(hour) || isNaN(minute)) return;\n if (d[3] && d[3].toLowerCase() === 'pm' && hour < 13) hour += 12;\n setValueISOFull(`T${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:00`, 1);\n },\n});\n</script>\n","<template>\n <input-base\n v-bind=\"{ ...props, loading } as any\"\n :class=\"densityClass\"\n clearable\n @click:clear=\"removeFile\"\n @blur=\"touched = true\"\n >\n <template #prepend-inner><cached-icon name=\"mdi-paperclip\" /></template>\n <template #loader>\n <v-progress-linear\n v-if=\"currentFile && progress < 100\"\n :model-value=\"progress\"\n :indeterminate=\"progress === -1\"\n />\n </template>\n <template #default=\"slotProps\">\n <div class=\"d-flex w-100 position-relative df-input-wrapper\" :class=\"density\">\n <v-file-input\n v-model=\"selectedFile\"\n :label=\"fileLabel\"\n density=\"compact\"\n variant=\"plain\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"vuetifyBindings.name\"\n :hide-details=\"true\"\n :show-size=\"true\"\n :multiple=\"false\"\n :style=\"currentFile && progress < 100 ? 'visibility: hidden' : ''\"\n :clearable=\"false\"\n v-bind=\"passthroughAttrs\"\n prepend-icon=\"\"\n @update:model-value=\"handleFileChange\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template v-if=\"canDownload\" #append-inner>\n <button\n type=\"button\"\n class=\"df-file-download-btn\"\n :title=\"t('FileDownload')\"\n :aria-label=\"t('FileDownload')\"\n @click.stop.prevent=\"downloadFile\"\n >\n <cached-icon name=\"mdi-download\" />\n </button>\n </template>\n </v-file-input>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfFileProps } from './dynamicforms-component-props';\nimport {\n BaseEmits,\n defaultBaseProps,\n InputBase,\n setFileGoneError,\n translate,\n useFileTouchKeepAlive,\n useInputBase,\n} from './helpers';\n\nconst props = withDefaults(defineProps<DfFileProps>(), defaultBaseProps);\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase(props, emits);\nconst t = translate;\n\n// State\nconst currentFile = ref<File | null>(null);\nconst progress = ref(0);\nconst selectedFile = ref<File | null>();\nconst loading = computed(() => currentFile.value && progress.value < 100);\n\nconst fileLabel = computed(() => {\n if (!selectedFile.value && value.value) {\n return value.value;\n }\n return '';\n});\n\nconst canDownload = computed(() => !selectedFile.value && !!value.value && !!props.comms.getDownloadUrl);\n\nasync function downloadFile() {\n if (!value.value || !props.comms.getDownloadUrl) return;\n\n const url = await props.comms.getDownloadUrl(value.value);\n const link = document.createElement('a');\n link.href = url;\n link.download = '';\n link.rel = 'noopener';\n link.click();\n}\n\nfunction resetFileState() {\n value.value = null;\n progress.value = 0;\n currentFile.value = null;\n selectedFile.value = null;\n clearTouchInterval();\n}\n\nfunction handleFileGone(errorText: string) {\n resetFileState();\n setFileGoneError(props.control, errorText);\n}\n\nconst { setupTouchInterval, clearTouchInterval } = useFileTouchKeepAlive(\n value,\n () => props.comms,\n () => props.touchInterval,\n handleFileGone,\n);\n\nasync function removeFile() {\n if (value.value) {\n await props.comms.delete(value.value);\n }\n\n resetFileState();\n touched.value = true;\n}\n\nasync function upload(file: File) {\n progress.value = -1;\n currentFile.value = file;\n\n try {\n value.value = await props.comms.upload(file, (loaded: number, total: number) => {\n progress.value = Math.round((loaded * 100) / total);\n });\n progress.value = 100;\n // a picked file concludes the edit: the file dialog and a drop have no blur of the field\n touched.value = true;\n setupTouchInterval();\n } catch (err) {\n progress.value = 0;\n currentFile.value = null;\n selectedFile.value = null;\n throw err;\n }\n}\n\nfunction handleFileChange(file: File | File[]): any {\n if (file) {\n if (Array.isArray(file)) {\n console.error('Uploading multiple files not supported right now');\n } else {\n upload(file);\n }\n }\n}\n</script>\n\n<style>\n.df-file-download-btn {\n display: inline-flex;\n align-items: center;\n cursor: pointer;\n opacity: 0.7;\n}\n.df-file-download-btn:hover {\n opacity: 1;\n}\n\n.df-input-wrapper .v-file-input--dragging {\n outline: 2px dashed rgb(var(--v-theme-primary));\n outline-offset: -2px;\n background-color: rgba(var(--v-theme-primary), 0.08);\n}\n</style>\n","<template>\n <input-base\n v-bind=\"{ ...props, loading } as any\"\n :class=\"densityClass\"\n clearable\n @click:clear=\"removeFile\"\n @blur=\"touched = true\"\n >\n <template #prepend-inner><cached-icon name=\"mdi-paperclip\" /></template>\n <template #loader>\n <v-progress-linear\n v-if=\"currentFile && progress < 100\"\n :model-value=\"progress\"\n :indeterminate=\"progress === -1\"\n />\n </template>\n <template #default=\"slotProps\">\n <div class=\"d-flex w-100 position-relative df-input-wrapper\" :class=\"density\">\n <v-file-input\n v-model=\"selectedFile\"\n :label=\"fileLabel\"\n density=\"compact\"\n variant=\"plain\"\n :readonly=\"vuetifyBindings.readonly\"\n :disabled=\"vuetifyBindings.disabled\"\n :name=\"vuetifyBindings.name\"\n :hide-details=\"true\"\n :show-size=\"true\"\n :multiple=\"false\"\n :style=\"currentFile && progress < 100 ? 'visibility: hidden' : ''\"\n :clearable=\"false\"\n v-bind=\"passthroughAttrs\"\n prepend-icon=\"\"\n @update:model-value=\"handleFileChange\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n >\n <template v-if=\"canDownload\" #append-inner>\n <button\n type=\"button\"\n class=\"df-file-download-btn\"\n :title=\"t('FileDownload')\"\n :aria-label=\"t('FileDownload')\"\n @click.stop.prevent=\"downloadFile\"\n >\n <cached-icon name=\"mdi-download\" />\n </button>\n </template>\n </v-file-input>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfFileProps } from './dynamicforms-component-props';\nimport {\n BaseEmits,\n defaultBaseProps,\n InputBase,\n setFileGoneError,\n translate,\n useFileTouchKeepAlive,\n useInputBase,\n} from './helpers';\n\nconst props = withDefaults(defineProps<DfFileProps>(), defaultBaseProps);\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase(props, emits);\nconst t = translate;\n\n// State\nconst currentFile = ref<File | null>(null);\nconst progress = ref(0);\nconst selectedFile = ref<File | null>();\nconst loading = computed(() => currentFile.value && progress.value < 100);\n\nconst fileLabel = computed(() => {\n if (!selectedFile.value && value.value) {\n return value.value;\n }\n return '';\n});\n\nconst canDownload = computed(() => !selectedFile.value && !!value.value && !!props.comms.getDownloadUrl);\n\nasync function downloadFile() {\n if (!value.value || !props.comms.getDownloadUrl) return;\n\n const url = await props.comms.getDownloadUrl(value.value);\n const link = document.createElement('a');\n link.href = url;\n link.download = '';\n link.rel = 'noopener';\n link.click();\n}\n\nfunction resetFileState() {\n value.value = null;\n progress.value = 0;\n currentFile.value = null;\n selectedFile.value = null;\n clearTouchInterval();\n}\n\nfunction handleFileGone(errorText: string) {\n resetFileState();\n setFileGoneError(props.control, errorText);\n}\n\nconst { setupTouchInterval, clearTouchInterval } = useFileTouchKeepAlive(\n value,\n () => props.comms,\n () => props.touchInterval,\n handleFileGone,\n);\n\nasync function removeFile() {\n if (value.value) {\n await props.comms.delete(value.value);\n }\n\n resetFileState();\n touched.value = true;\n}\n\nasync function upload(file: File) {\n progress.value = -1;\n currentFile.value = file;\n\n try {\n value.value = await props.comms.upload(file, (loaded: number, total: number) => {\n progress.value = Math.round((loaded * 100) / total);\n });\n progress.value = 100;\n // a picked file concludes the edit: the file dialog and a drop have no blur of the field\n touched.value = true;\n setupTouchInterval();\n } catch (err) {\n progress.value = 0;\n currentFile.value = null;\n selectedFile.value = null;\n throw err;\n }\n}\n\nfunction handleFileChange(file: File | File[]): any {\n if (file) {\n if (Array.isArray(file)) {\n console.error('Uploading multiple files not supported right now');\n } else {\n upload(file);\n }\n }\n}\n</script>\n\n<style>\n.df-file-download-btn {\n display: inline-flex;\n align-items: center;\n cursor: pointer;\n opacity: 0.7;\n}\n.df-file-download-btn:hover {\n opacity: 1;\n}\n\n.df-input-wrapper .v-file-input--dragging {\n outline: 2px dashed rgb(var(--v-theme-primary));\n outline-offset: -2px;\n background-color: rgba(var(--v-theme-primary), 0.08);\n}\n</style>\n","<template>\n <input-base\n v-bind=\"{ ...props, loading } as any\"\n class=\"df-image-field\"\n :class=\"densityClass\"\n clearable\n @click:clear=\"removeFile\"\n @blur=\"touched = true\"\n >\n <template #prepend-inner><cached-icon name=\"mdi-image\" /></template>\n <template #loader>\n <v-progress-linear\n v-if=\"currentFile && progress < 100\"\n :model-value=\"progress\"\n :indeterminate=\"progress === -1\"\n />\n </template>\n <template #default=\"slotProps\">\n <!-- click.stop: v-field's own click handler calls preventDefault whenever the click target isn't already\n the focused element, which would silently cancel a <label>'s file-picker default action before it\n can reach the input it targets. -->\n <div\n class=\"d-flex w-100 position-relative df-input-wrapper df-image-wrapper\"\n :class=\"[density, { 'df-image-dragging': isDragging, 'df-image-disabled': isDisabled }]\"\n @dragenter.prevent=\"onDragEnter\"\n @dragover.prevent\n @dragleave.prevent=\"onDragLeave\"\n @drop.prevent=\"onDrop\"\n @click.stop\n >\n <input\n :id=\"fileInputId\"\n ref=\"fileInputRef\"\n type=\"file\"\n accept=\"image/*\"\n class=\"df-image-native-input\"\n :disabled=\"isDisabled\"\n :name=\"vuetifyBindings.name\"\n @change=\"onNativeChange\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n />\n <label v-if=\"previewUrl\" :for=\"fileInputId\" class=\"df-image-preview-label\">\n <v-img\n :src=\"previewUrl\"\n class=\"df-image-preview\"\n :style=\"currentFile && progress < 100 ? 'visibility: hidden' : ''\"\n />\n </label>\n <label v-else :for=\"fileInputId\" class=\"df-image-placeholder\">\n <cached-icon name=\"mdi-tray-arrow-up\" />\n <span>{{ t('ImageDropHint') }}</span>\n </label>\n <label\n v-if=\"previewUrl && !isDisabled\"\n :for=\"fileInputId\"\n class=\"df-image-replace-btn\"\n :title=\"t('ImageReplace')\"\n >\n <cached-icon name=\"mdi-pencil\" />\n </label>\n <a\n v-if=\"canDownload\"\n :href=\"value as string\"\n download\n target=\"_blank\"\n rel=\"noopener\"\n class=\"df-image-download-btn\"\n :title=\"t('ImageDownload')\"\n :aria-label=\"t('ImageDownload')\"\n >\n <cached-icon name=\"mdi-download\" />\n </a>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, useId } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfImageProps } from './dynamicforms-component-props';\nimport {\n BaseEmits,\n defaultBaseProps,\n InputBase,\n setFileGoneError,\n translate,\n useFileTouchKeepAlive,\n useInputBase,\n} from './helpers';\n\nconst props = withDefaults(defineProps<DfImageProps>(), defaultBaseProps);\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase(props, emits);\nconst t = translate;\nconst fileInputId = useId();\n\n// State\nconst currentFile = ref<File | null>(null);\nconst progress = ref(0);\nconst objectUrl = ref<string | null>(null);\nconst dragCounter = ref(0);\nconst fileInputRef = ref<HTMLInputElement | null>(null);\n\nconst loading = computed(() => currentFile.value && progress.value < 100);\nconst isDisabled = computed(() => !!(vuetifyBindings.value.disabled || vuetifyBindings.value.readonly));\nconst isDragging = computed(() => dragCounter.value > 0);\nconst previewUrl = computed<string | null>(() => objectUrl.value ?? (value.value ? (value.value as string) : null));\nconst canDownload = computed(() => !!value.value);\n\nfunction revokeObjectUrl() {\n if (objectUrl.value) {\n URL.revokeObjectURL(objectUrl.value);\n objectUrl.value = null;\n }\n}\n\nfunction resetFileState() {\n value.value = null;\n progress.value = 0;\n currentFile.value = null;\n revokeObjectUrl();\n clearTouchInterval();\n}\n\nfunction handleFileGone(errorText: string) {\n resetFileState();\n setFileGoneError(props.control, errorText);\n}\n\nconst { setupTouchInterval, clearTouchInterval } = useFileTouchKeepAlive(\n value,\n () => props.comms,\n () => props.touchInterval,\n handleFileGone,\n);\n\nonBeforeUnmount(() => revokeObjectUrl());\n\nasync function removeFile() {\n if (value.value) {\n await props.comms.delete(value.value);\n }\n\n resetFileState();\n touched.value = true;\n}\n\nasync function upload(file: File) {\n progress.value = -1;\n currentFile.value = file;\n revokeObjectUrl();\n objectUrl.value = URL.createObjectURL(file);\n\n try {\n value.value = await props.comms.upload(file, (loaded: number, total: number) => {\n progress.value = Math.round((loaded * 100) / total);\n });\n progress.value = 100;\n // a picked file concludes the edit: the file dialog and a drop have no blur of the field\n touched.value = true;\n setupTouchInterval();\n } catch (err) {\n progress.value = 0;\n currentFile.value = null;\n revokeObjectUrl();\n throw err;\n }\n}\n\nfunction handleFile(file: File) {\n if (!file.type.startsWith('image/')) {\n console.error('Only image files are supported');\n return;\n }\n upload(file);\n}\n\nfunction onNativeChange(event: Event) {\n const input = event.target as HTMLInputElement;\n const file = input.files?.[0];\n input.value = '';\n if (file) handleFile(file);\n}\n\nfunction onDragEnter() {\n if (isDisabled.value) return;\n dragCounter.value += 1;\n}\nfunction onDragLeave() {\n dragCounter.value = Math.max(0, dragCounter.value - 1);\n}\nfunction onDrop(event: DragEvent) {\n dragCounter.value = 0;\n if (isDisabled.value) return;\n const file = event.dataTransfer?.files?.[0];\n if (file) handleFile(file);\n}\n</script>\n\n<style>\n/* .df-sub-field caps itself at the height of a single-line input; without lifting that cap here, the taller\n image area would keep the field's own layout box small and just paint over whatever follows it on the page. */\n.df-image-field .df-sub-field {\n max-height: revert;\n}\n\n.df-image-wrapper {\n height: 160px;\n border: 1px dashed rgba(128, 128, 128, 0.5);\n border-radius: 4px;\n overflow: hidden;\n}\n.df-image-wrapper.df-image-dragging {\n border-color: rgb(var(--v-theme-primary));\n background-color: rgba(var(--v-theme-primary), 0.08);\n}\n.df-image-wrapper.df-image-disabled .df-image-placeholder,\n.df-image-wrapper.df-image-disabled .df-image-preview-label {\n cursor: not-allowed;\n}\n\n/* Visually hidden but focusable (keyboard-reachable) and clickable via its <label>s. */\n.df-image-native-input {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n opacity: 0;\n}\n.df-image-native-input:focus-visible ~ label {\n outline: 2px solid rgb(var(--v-theme-primary));\n outline-offset: -2px;\n}\n\n.df-image-preview-label,\n.df-image-preview {\n display: block;\n width: 100%;\n height: 100%;\n}\n/* a host page's own typography reset (e.g. margin on bare <img> tags) would otherwise offset v-img's <img> from\n the box it's meant to fill exactly, clipping it against .df-image-wrapper's overflow:hidden */\n.df-image-preview img {\n margin: 0;\n}\n.df-image-preview-label {\n cursor: pointer;\n}\n\n.df-image-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 4px;\n width: 100%;\n height: 100%;\n cursor: pointer;\n color: inherit;\n opacity: 0.7;\n}\n\n.df-image-replace-btn,\n.df-image-download-btn {\n position: absolute;\n top: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n cursor: pointer;\n background-color: rgba(var(--v-theme-surface), 0.9);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n.df-image-replace-btn {\n right: 4px;\n}\n.df-image-download-btn {\n left: 4px;\n color: inherit;\n}\n</style>\n","<template>\n <input-base\n v-bind=\"{ ...props, loading } as any\"\n class=\"df-image-field\"\n :class=\"densityClass\"\n clearable\n @click:clear=\"removeFile\"\n @blur=\"touched = true\"\n >\n <template #prepend-inner><cached-icon name=\"mdi-image\" /></template>\n <template #loader>\n <v-progress-linear\n v-if=\"currentFile && progress < 100\"\n :model-value=\"progress\"\n :indeterminate=\"progress === -1\"\n />\n </template>\n <template #default=\"slotProps\">\n <!-- click.stop: v-field's own click handler calls preventDefault whenever the click target isn't already\n the focused element, which would silently cancel a <label>'s file-picker default action before it\n can reach the input it targets. -->\n <div\n class=\"d-flex w-100 position-relative df-input-wrapper df-image-wrapper\"\n :class=\"[density, { 'df-image-dragging': isDragging, 'df-image-disabled': isDisabled }]\"\n @dragenter.prevent=\"onDragEnter\"\n @dragover.prevent\n @dragleave.prevent=\"onDragLeave\"\n @drop.prevent=\"onDrop\"\n @click.stop\n >\n <input\n :id=\"fileInputId\"\n ref=\"fileInputRef\"\n type=\"file\"\n accept=\"image/*\"\n class=\"df-image-native-input\"\n :disabled=\"isDisabled\"\n :name=\"vuetifyBindings.name\"\n @change=\"onNativeChange\"\n @focus=\"slotProps.focus()\"\n @blur=\"slotProps.blur()\"\n />\n <label v-if=\"previewUrl\" :for=\"fileInputId\" class=\"df-image-preview-label\">\n <v-img\n :src=\"previewUrl\"\n class=\"df-image-preview\"\n :style=\"currentFile && progress < 100 ? 'visibility: hidden' : ''\"\n />\n </label>\n <label v-else :for=\"fileInputId\" class=\"df-image-placeholder\">\n <cached-icon name=\"mdi-tray-arrow-up\" />\n <span>{{ t('ImageDropHint') }}</span>\n </label>\n <label\n v-if=\"previewUrl && !isDisabled\"\n :for=\"fileInputId\"\n class=\"df-image-replace-btn\"\n :title=\"t('ImageReplace')\"\n >\n <cached-icon name=\"mdi-pencil\" />\n </label>\n <a\n v-if=\"canDownload\"\n :href=\"value as string\"\n download\n target=\"_blank\"\n rel=\"noopener\"\n class=\"df-image-download-btn\"\n :title=\"t('ImageDownload')\"\n :aria-label=\"t('ImageDownload')\"\n >\n <cached-icon name=\"mdi-download\" />\n </a>\n </div>\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, useId } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { DfImageProps } from './dynamicforms-component-props';\nimport {\n BaseEmits,\n defaultBaseProps,\n InputBase,\n setFileGoneError,\n translate,\n useFileTouchKeepAlive,\n useInputBase,\n} from './helpers';\n\nconst props = withDefaults(defineProps<DfImageProps>(), defaultBaseProps);\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { density, densityClass, touched, value, vuetifyBindings } = useInputBase(props, emits);\nconst t = translate;\nconst fileInputId = useId();\n\n// State\nconst currentFile = ref<File | null>(null);\nconst progress = ref(0);\nconst objectUrl = ref<string | null>(null);\nconst dragCounter = ref(0);\nconst fileInputRef = ref<HTMLInputElement | null>(null);\n\nconst loading = computed(() => currentFile.value && progress.value < 100);\nconst isDisabled = computed(() => !!(vuetifyBindings.value.disabled || vuetifyBindings.value.readonly));\nconst isDragging = computed(() => dragCounter.value > 0);\nconst previewUrl = computed<string | null>(() => objectUrl.value ?? (value.value ? (value.value as string) : null));\nconst canDownload = computed(() => !!value.value);\n\nfunction revokeObjectUrl() {\n if (objectUrl.value) {\n URL.revokeObjectURL(objectUrl.value);\n objectUrl.value = null;\n }\n}\n\nfunction resetFileState() {\n value.value = null;\n progress.value = 0;\n currentFile.value = null;\n revokeObjectUrl();\n clearTouchInterval();\n}\n\nfunction handleFileGone(errorText: string) {\n resetFileState();\n setFileGoneError(props.control, errorText);\n}\n\nconst { setupTouchInterval, clearTouchInterval } = useFileTouchKeepAlive(\n value,\n () => props.comms,\n () => props.touchInterval,\n handleFileGone,\n);\n\nonBeforeUnmount(() => revokeObjectUrl());\n\nasync function removeFile() {\n if (value.value) {\n await props.comms.delete(value.value);\n }\n\n resetFileState();\n touched.value = true;\n}\n\nasync function upload(file: File) {\n progress.value = -1;\n currentFile.value = file;\n revokeObjectUrl();\n objectUrl.value = URL.createObjectURL(file);\n\n try {\n value.value = await props.comms.upload(file, (loaded: number, total: number) => {\n progress.value = Math.round((loaded * 100) / total);\n });\n progress.value = 100;\n // a picked file concludes the edit: the file dialog and a drop have no blur of the field\n touched.value = true;\n setupTouchInterval();\n } catch (err) {\n progress.value = 0;\n currentFile.value = null;\n revokeObjectUrl();\n throw err;\n }\n}\n\nfunction handleFile(file: File) {\n if (!file.type.startsWith('image/')) {\n console.error('Only image files are supported');\n return;\n }\n upload(file);\n}\n\nfunction onNativeChange(event: Event) {\n const input = event.target as HTMLInputElement;\n const file = input.files?.[0];\n input.value = '';\n if (file) handleFile(file);\n}\n\nfunction onDragEnter() {\n if (isDisabled.value) return;\n dragCounter.value += 1;\n}\nfunction onDragLeave() {\n dragCounter.value = Math.max(0, dragCounter.value - 1);\n}\nfunction onDrop(event: DragEvent) {\n dragCounter.value = 0;\n if (isDisabled.value) return;\n const file = event.dataTransfer?.files?.[0];\n if (file) handleFile(file);\n}\n</script>\n\n<style>\n/* .df-sub-field caps itself at the height of a single-line input; without lifting that cap here, the taller\n image area would keep the field's own layout box small and just paint over whatever follows it on the page. */\n.df-image-field .df-sub-field {\n max-height: revert;\n}\n\n.df-image-wrapper {\n height: 160px;\n border: 1px dashed rgba(128, 128, 128, 0.5);\n border-radius: 4px;\n overflow: hidden;\n}\n.df-image-wrapper.df-image-dragging {\n border-color: rgb(var(--v-theme-primary));\n background-color: rgba(var(--v-theme-primary), 0.08);\n}\n.df-image-wrapper.df-image-disabled .df-image-placeholder,\n.df-image-wrapper.df-image-disabled .df-image-preview-label {\n cursor: not-allowed;\n}\n\n/* Visually hidden but focusable (keyboard-reachable) and clickable via its <label>s. */\n.df-image-native-input {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n opacity: 0;\n}\n.df-image-native-input:focus-visible ~ label {\n outline: 2px solid rgb(var(--v-theme-primary));\n outline-offset: -2px;\n}\n\n.df-image-preview-label,\n.df-image-preview {\n display: block;\n width: 100%;\n height: 100%;\n}\n/* a host page's own typography reset (e.g. margin on bare <img> tags) would otherwise offset v-img's <img> from\n the box it's meant to fill exactly, clipping it against .df-image-wrapper's overflow:hidden */\n.df-image-preview img {\n margin: 0;\n}\n.df-image-preview-label {\n cursor: pointer;\n}\n\n.df-image-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 4px;\n width: 100%;\n height: 100%;\n cursor: pointer;\n color: inherit;\n opacity: 0.7;\n}\n\n.df-image-replace-btn,\n.df-image-download-btn {\n position: absolute;\n top: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n cursor: pointer;\n background-color: rgba(var(--v-theme-surface), 0.9);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n.df-image-replace-btn {\n right: 4px;\n}\n.df-image-download-btn {\n left: 4px;\n color: inherit;\n}\n</style>\n","<template>\n <div v-if=\"isRendered\" class=\"df-input-container\" :class=\"[densityClass, visibilityClass]\">\n <v-text-field\n v-if=\"!isNumber\"\n v-model=\"value\"\n :type=\"inputType\"\n v-bind=\"vuetifyBindings as any\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n </v-text-field>\n <v-number-input\n v-else\n v-model=\"value\"\n density=\"compact\"\n control-variant=\"stacked\"\n v-bind=\"{ ...vuetifyBindings, ...numberInputBindings } as any\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n </v-number-input>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, toRefs, unref } from 'vue';\n\nimport { DfInputProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfInputProps>(), {\n ...defaultBaseProps,\n inputType: 'text',\n precision: null,\n step: undefined,\n min: undefined,\n max: undefined,\n});\n\ninterface Emits extends BaseEmits {}\n\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, shownErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\nconst { inputType, max, min, precision, step } = toRefs(props);\n\nconst isNumber = computed(() => inputType.value === 'number');\nconst numberInputBindings = computed(() =>\n !isNumber.value ? {} : { min: unref(min), max: unref(max), precision: unref(precision), step: unref(step) },\n);\n</script>\n","<template>\n <div v-if=\"isRendered\" class=\"df-input-container\" :class=\"[densityClass, visibilityClass]\">\n <v-text-field\n v-if=\"!isNumber\"\n v-model=\"value\"\n :type=\"inputType\"\n v-bind=\"vuetifyBindings as any\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n </v-text-field>\n <v-number-input\n v-else\n v-model=\"value\"\n density=\"compact\"\n control-variant=\"stacked\"\n v-bind=\"{ ...vuetifyBindings, ...numberInputBindings } as any\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n </v-number-input>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, toRefs, unref } from 'vue';\n\nimport { DfInputProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfInputProps>(), {\n ...defaultBaseProps,\n inputType: 'text',\n precision: null,\n step: undefined,\n min: undefined,\n max: undefined,\n});\n\ninterface Emits extends BaseEmits {}\n\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, shownErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\nconst { inputType, max, min, precision, step } = toRefs(props);\n\nconst isNumber = computed(() => inputType.value === 'number');\nconst numberInputBindings = computed(() =>\n !isNumber.value ? {} : { min: unref(min), max: unref(max), precision: unref(precision), step: unref(step) },\n);\n</script>\n","import { Editor, Extension, Mark, mergeAttributes } from '@tiptap/core';\n\n/**\n * Adds a `class` attribute to paragraph, heading, blockquote and code-block nodes, so the \"Style\" dropdown's\n * named looks (`h3.category`, `p.info-box`, `pre.fancy-code-dark`...) persist through `getHTML()`/`setContent()`\n * the same way any other node attribute does.\n */\nexport const ClassAttribute = Extension.create({\n name: 'classAttribute',\n addGlobalAttributes() {\n return [\n {\n types: ['paragraph', 'heading', 'blockquote', 'codeBlock'],\n attributes: {\n class: {\n default: null,\n parseHTML: (element: HTMLElement) => element.getAttribute('class'),\n renderHTML: (attributes: Record<string, any>) => (attributes.class ? { class: attributes.class } : {}),\n },\n },\n },\n ];\n },\n});\n\nfunction styledSpanMark(name: string, className: string) {\n return Mark.create({\n name,\n parseHTML() {\n return [{ tag: `span.${className}` }];\n },\n renderHTML({ HTMLAttributes }) {\n return ['span', mergeAttributes(HTMLAttributes, { class: className }), 0];\n },\n });\n}\n\n/** Toggle mark wrapping the selection in `<span class=\"marker\">`, behaving like bold/italic over a selection. */\nexport const Marker = styledSpanMark('marker', 'marker');\n/** Toggle mark wrapping the selection in `<span class=\"spoiler\">`, behaving like bold/italic over a selection. */\nexport const Spoiler = styledSpanMark('spoiler', 'spoiler');\n\ninterface BlockStyleDef {\n key: 'ArticleCategory' | 'Title' | 'Subtitle' | 'InfoBox' | 'SideQuote' | 'CodeDark' | 'CodeBright';\n kind: 'heading' | 'paragraph' | 'blockquote' | 'codeBlock';\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n className: string;\n}\n\ninterface MarkStyleDef {\n key: 'Marker' | 'Spoiler';\n kind: 'mark';\n markName: 'marker' | 'spoiler';\n}\n\nexport type StyleDef = BlockStyleDef | MarkStyleDef;\n\n/** The \"Style\" dropdown's entries, in the order they are listed - element/class pairs the toolbar applies. */\nexport const STYLE_DEFS: StyleDef[] = [\n { key: 'ArticleCategory', kind: 'heading', level: 3, className: 'category' },\n { key: 'Title', kind: 'heading', level: 2, className: 'document-title' },\n { key: 'Subtitle', kind: 'heading', level: 3, className: 'document-subtitle' },\n { key: 'InfoBox', kind: 'paragraph', className: 'info-box' },\n { key: 'SideQuote', kind: 'blockquote', className: 'side-quote' },\n { key: 'Marker', kind: 'mark', markName: 'marker' },\n { key: 'Spoiler', kind: 'mark', markName: 'spoiler' },\n { key: 'CodeDark', kind: 'codeBlock', className: 'fancy-code fancy-code-dark' },\n { key: 'CodeBright', kind: 'codeBlock', className: 'fancy-code fancy-code-bright' },\n];\n\n// `editor.isActive(type, attrs)` requires every node touched by the current selection to match, so a\n// selection that spans a styled block plus the empty trailing paragraph TipTap keeps after it (or, after\n// `selectAll` on a single-block document, the whole document) reports no match even though the block the\n// selection starts in carries the style. Reading off the selection's anchor node instead answers the question\n// the dropdown actually asks: \"does the block/mark the selection starts in carry this style\".\n//\n// `$from` for a whole-document `AllSelection` resolves at depth 0 (the boundary before the first child, not\n// inside it), so a depth-0 anchor is re-resolved one position in - a position guaranteed to sit inside the\n// document's first block.\nfunction anchorPos(editor: Editor) {\n const { state } = editor;\n const { $from } = state.selection;\n if ($from.depth > 0 || state.doc.content.size === 0) return $from;\n return state.doc.resolve(Math.min(1, state.doc.content.size));\n}\n\nfunction anchorNode(editor: Editor) {\n return anchorPos(editor).parent;\n}\n\nfunction anchorAncestor(editor: Editor, typeName: string) {\n const $pos = anchorPos(editor);\n for (let depth = $pos.depth; depth >= 0; depth -= 1) {\n if ($pos.node(depth).type.name === typeName) return $pos.node(depth);\n }\n return null;\n}\n\nexport function isStyleActive(editor: Editor, def: StyleDef): boolean {\n switch (def.kind) {\n case 'heading': {\n const node = anchorNode(editor);\n return node.type.name === 'heading' && node.attrs.level === def.level && node.attrs.class === def.className;\n }\n case 'paragraph': {\n const node = anchorNode(editor);\n return node.type.name === 'paragraph' && node.attrs.class === def.className;\n }\n case 'codeBlock': {\n const node = anchorNode(editor);\n return node.type.name === 'codeBlock' && node.attrs.class === def.className;\n }\n case 'blockquote': {\n const node = anchorAncestor(editor, 'blockquote');\n return !!node && node.attrs.class === def.className;\n }\n case 'mark':\n return editor.isActive(def.markName);\n default:\n return false;\n }\n}\n\n/**\n * Applies (or, over an already-styled block/selection, removes) one \"Style\" dropdown entry. Block styles both\n * set the node type and its class in one step; the two inline marks toggle over the current selection like bold\n * or italic.\n */\nexport function applyStyle(editor: Editor, def: StyleDef): void {\n const chain = editor.chain().focus();\n\n // `lift` (which `unsetBlockquote` calls) only acts when every node the selection touches matches the target\n // type - a whole-document `AllSelection` (as `selectAll` produces) also touches the trailing empty paragraph\n // TipTap keeps after the last block, so it never matches and the command silently no-ops. Collapsing such a\n // selection down to the anchor block first keeps every block command below scoped to the block the dropdown\n // means. The two marks are left alone - they need the real selection range to wrap the marked text in.\n const { $from } = editor.state.selection;\n if (def.kind !== 'mark' && $from.depth === 0 && editor.state.doc.content.size > 0) {\n chain.setTextSelection(anchorPos(editor).pos);\n }\n\n switch (def.kind) {\n case 'heading':\n if (isStyleActive(editor, def)) chain.setParagraph().updateAttributes('paragraph', { class: null }).run();\n else {\n chain.setNode('heading', { level: def.level }).updateAttributes('heading', { class: def.className }).run();\n }\n break;\n case 'paragraph':\n if (isStyleActive(editor, def)) chain.setParagraph().updateAttributes('paragraph', { class: null }).run();\n else chain.setParagraph().updateAttributes('paragraph', { class: def.className }).run();\n break;\n case 'blockquote':\n if (isStyleActive(editor, def)) chain.unsetBlockquote().run();\n else if (anchorAncestor(editor, 'blockquote')) {\n chain.updateAttributes('blockquote', { class: def.className }).run();\n } else chain.setBlockquote().updateAttributes('blockquote', { class: def.className }).run();\n break;\n case 'codeBlock':\n if (isStyleActive(editor, def)) chain.toggleCodeBlock().updateAttributes('paragraph', { class: null }).run();\n else if (anchorNode(editor).type.name === 'codeBlock') {\n chain.updateAttributes('codeBlock', { class: def.className }).run();\n } else chain.setCodeBlock().updateAttributes('codeBlock', { class: def.className }).run();\n break;\n case 'mark':\n chain.toggleMark(def.markName).run();\n break;\n default:\n break;\n }\n}\n","import { Fragment, Node as PMNode, Slice } from '@tiptap/pm/model';\nimport { EditorView } from '@tiptap/pm/view';\nimport { Editor } from '@tiptap/vue-3';\n\n/** Reads a `File` into a base64 `data:` URI - the same embedding an uploaded or dropped image goes through. */\nexport function fileToDataUrl(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n}\n\n/**\n * The image files carried alongside (or instead of) HTML on a clipboard paste. Copying a picture out of another\n * app, or a Word/Docs selection that contains embedded pictures, delivers the pixel data this way rather than as\n * an inline `data:` URI in the HTML - `items` covers Chromium and Firefox, `files` is the fallback where a\n * browser only populates that.\n */\nexport function extractImageFiles(dataTransfer: DataTransfer | null): File[] {\n if (!dataTransfer) return [];\n const files: File[] = [];\n Array.from(dataTransfer.items || []).forEach((item) => {\n if (item.kind === 'file') {\n const file = item.getAsFile();\n if (file && file.type.startsWith('image/')) files.push(file);\n }\n });\n if (files.length === 0) {\n Array.from(dataTransfer.files || []).forEach((file) => {\n if (file.type.startsWith('image/')) files.push(file);\n });\n }\n return files;\n}\n\nfunction countImageNodes(fragment: Fragment): number {\n let count = 0;\n fragment.forEach((node) => {\n if (node.type.name === 'image') count += 1;\n else if (node.content.size) count += countImageNodes(node.content);\n });\n return count;\n}\n\nfunction replaceImageSources(fragment: Fragment, urls: string[], cursor: { index: number }): Fragment {\n const children: PMNode[] = [];\n fragment.forEach((node) => {\n if (node.type.name === 'image' && cursor.index < urls.length) {\n children.push(node.type.create({ ...node.attrs, src: urls[cursor.index] }, node.content, node.marks));\n cursor.index += 1;\n } else if (node.content.size) {\n children.push(node.copy(replaceImageSources(node.content, urls, cursor)));\n } else {\n children.push(node);\n }\n });\n return Fragment.fromArray(children);\n}\n\n/**\n * A `handlePaste` for `editorProps`: when the clipboard carries image files, embeds each as a base64 `data:` URI\n * and either drops it into the `<img>` placeholders the pasted HTML already parsed into (order-matched - the\n * shape a Word/Docs selection with embedded pictures takes once `transformPastedHTML` and the schema have parsed\n * it into `slice`), or, where the paste held no HTML worth keeping, inserts the images as new nodes at the\n * selection. Non-image pastes are left to the editor's default handling by returning `false`.\n */\nexport function createImagePasteHandler(getEditor: () => Editor | undefined) {\n return (view: EditorView, event: ClipboardEvent, slice: Slice): boolean => {\n const files = extractImageFiles(event.clipboardData);\n if (files.length === 0) return false;\n\n event.preventDefault();\n\n Promise.all(files.map(fileToDataUrl)).then((urls) => {\n if (countImageNodes(slice.content) > 0) {\n const content = replaceImageSources(slice.content, urls, { index: 0 });\n const newSlice = new Slice(content, slice.openStart, slice.openEnd);\n view.dispatch(view.state.tr.replaceSelection(newSlice).scrollIntoView());\n return;\n }\n\n getEditor()\n ?.chain()\n .focus()\n .insertContent(urls.map((src) => ({ type: 'image', attrs: { src } })))\n .run();\n });\n\n return true;\n };\n}\n","import Link from '@tiptap/extension-link';\n\n/**\n * `Link`, with a `download` attribute the toolbar's \"Downloadable\" toggle can set - rendered as `download=\"file\"`\n * on the anchor.\n */\nexport const LinkWithDownload = Link.extend({\n name: 'link',\n addAttributes() {\n return {\n ...this.parent?.(),\n download: {\n default: null,\n parseHTML: (element: HTMLElement) => element.getAttribute('download'),\n renderHTML: (attributes: Record<string, any>) => (attributes.download ? { download: attributes.download } : {}),\n },\n };\n },\n});\n","import { mergeAttributes, Node } from '@tiptap/core';\n\n/**\n * Recognises a YouTube or Vimeo watch/share URL and returns the equivalent embeddable player URL, or `null` for\n * anything else - the toolbar falls back to inserting the URL as a plain link when this returns `null`.\n */\nexport function toEmbedSrc(url: string): string | null {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n\n const host = parsed.hostname.replace(/^www\\.|^m\\./, '');\n\n if (host === 'youtube.com') {\n const id = parsed.searchParams.get('v');\n if (id) return `https://www.youtube.com/embed/${id}`;\n const embedMatch = parsed.pathname.match(/^\\/embed\\/([\\w-]+)/);\n if (embedMatch) return `https://www.youtube.com/embed/${embedMatch[1]}`;\n const shortsMatch = parsed.pathname.match(/^\\/shorts\\/([\\w-]+)/);\n if (shortsMatch) return `https://www.youtube.com/embed/${shortsMatch[1]}`;\n return null;\n }\n\n if (host === 'youtu.be') {\n const id = parsed.pathname.slice(1);\n return id ? `https://www.youtube.com/embed/${id}` : null;\n }\n\n if (host === 'vimeo.com') {\n const id = parsed.pathname.split('/').filter(Boolean).pop();\n return id && /^\\d+$/.test(id) ? `https://player.vimeo.com/video/${id}` : null;\n }\n\n return null;\n}\n\n/**\n * A responsive `<iframe>` block for a recognised video URL (YouTube, Vimeo) - saved in `getHTML()` output as a\n * plain `iframe.media-embed`, with the responsive 16:9 sizing coming from the editor's own CSS rather than\n * inline styles, so the saved HTML stays provider-agnostic.\n */\nexport const MediaEmbed = Node.create({\n name: 'mediaEmbed',\n group: 'block',\n atom: true,\n draggable: true,\n addAttributes() {\n return {\n src: { default: null },\n };\n },\n parseHTML() {\n return [{ tag: 'iframe.media-embed' }];\n },\n renderHTML({ HTMLAttributes }) {\n return [\n 'iframe',\n mergeAttributes(\n {\n class: 'media-embed',\n frameborder: '0',\n allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture',\n allowfullscreen: 'true',\n },\n HTMLAttributes,\n ),\n ];\n },\n});\n","import { Editor } from '@tiptap/vue-3';\nimport { onBeforeUnmount, Ref, ref, watch } from 'vue';\n\n/**\n * A counter bumped on every editor transaction, and on every `update` (which `setEditable()` emits on its own,\n * without a transaction, to report an editable-state change). The `Editor` instance is not a reactive object, so\n * nothing else tells Vue that `editor.isActive(...)`/`editor.can()...`/`editor.isEditable` now answer differently -\n * a computed that reads this counter before calling them re-evaluates exactly when the editor's state actually\n * changed.\n */\nexport function useEditorTick(editorRef: Ref<Editor | undefined>) {\n const tick = ref(0);\n let bound: Editor | undefined;\n\n const onTick = () => {\n tick.value += 1;\n };\n const bind = (next: Editor | undefined) => {\n bound?.off('transaction', onTick);\n bound?.off('update', onTick);\n bound = next;\n bound?.on('transaction', onTick);\n bound?.on('update', onTick);\n };\n\n watch(editorRef, bind, { immediate: true });\n onBeforeUnmount(() => bind(undefined));\n\n return tick;\n}\n","<template>\n <div class=\"rtf-toolbar\" :class=\"{ 'rtf-toolbar--disabled': !editable }\">\n <df-actions :actions=\"undoRedoActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n rounded=\"sm\"\n :title=\"t('SelectAll')\"\n @click=\"editor?.chain().focus().selectAll().run()\"\n >\n <cached-icon name=\"mdi-select-all\" />\n </v-btn>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" append-icon=\"mdi-chevron-down\">\n {{ headingLabel }}\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item\n v-for=\"option in headingOptions\"\n :key=\"option.level\"\n :active=\"isHeadingActive(option.level)\"\n @click=\"setHeading(option.level)\"\n >\n <v-list-item-title>{{ option.label }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" append-icon=\"mdi-chevron-down\">\n {{ t('Style') }}\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item\n v-for=\"def in styleDefs\"\n :key=\"def.key\"\n :active=\"styleActive(def)\"\n @click=\"editor && applyStyle(editor, def)\"\n >\n <v-list-item-title>{{ t(def.key) }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"boldItalicActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <div class=\"rtf-toolbar-group\">\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n :title=\"t('HorizontalLine')\"\n @click=\"editor?.chain().focus().setHorizontalRule().run()\"\n >\n <cached-icon name=\"mdi-minus\" />\n </v-btn>\n\n <v-menu :close-on-content-click=\"false\" @update:model-value=\"(shown: boolean) => shown && openLinkMenu()\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t('Link')\" :active=\"state.link\">\n <cached-icon name=\"mdi-link-variant\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"linkUrl\"\n :label=\"t('LinkUrl')\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"applyLink\"\n />\n <v-checkbox\n v-model=\"linkDownloadable\"\n :label=\"t('Downloadable')\"\n density=\"compact\"\n hide-details\n class=\"mt-1\"\n />\n <div class=\"d-flex justify-end ga-2 mt-2\">\n <v-btn v-if=\"state.link\" size=\"small\" variant=\"text\" @click=\"removeLink\">{{ t('LinkRemove') }}</v-btn>\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"applyLink\">{{ t('LinkApply') }}</v-btn>\n </div>\n </v-card>\n </v-menu>\n\n <v-menu :close-on-content-click=\"false\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t('Image')\">\n <cached-icon name=\"mdi-image-plus\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"imageUrl\"\n :label=\"t('ImageUrl')\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"insertImageFromUrl\"\n />\n <div class=\"d-flex justify-space-between align-center ga-2 mt-2\">\n <v-btn size=\"small\" variant=\"text\" prepend-icon=\"mdi-upload\" @click=\"triggerImageUpload\">\n {{ t('ImageUpload') }}\n </v-btn>\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"insertImageFromUrl\">\n {{ t('ImageInsert') }}\n </v-btn>\n </div>\n </v-card>\n </v-menu>\n <input ref=\"imageInput\" type=\"file\" accept=\"image/*\" class=\"d-none\" @change=\"onImageFileChosen\" />\n\n <v-menu :close-on-content-click=\"false\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t('MediaEmbed')\">\n <cached-icon name=\"mdi-video-plus\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"embedUrl\"\n :label=\"t('MediaEmbedUrl')\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"insertMediaEmbed\"\n />\n <div class=\"d-flex justify-end mt-2\">\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"insertMediaEmbed\">\n {{ t('MediaEmbedInsert') }}\n </v-btn>\n </div>\n </v-card>\n </v-menu>\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t('Table')\">\n <cached-icon name=\"mdi-table\" />\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item @click=\"editor?.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()\">\n <template #prepend><cached-icon name=\"mdi-table-plus\" /></template>\n <v-list-item-title>{{ t('TableInsert') }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addRowBefore().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-plus-before\" /></template>\n <v-list-item-title>{{ t('TableAddRowAbove') }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addRowAfter().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-plus-after\" /></template>\n <v-list-item-title>{{ t('TableAddRowBelow') }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteRow().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-remove\" /></template>\n <v-list-item-title>{{ t('TableDeleteRow') }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addColumnBefore().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-plus-before\" /></template>\n <v-list-item-title>{{ t('TableAddColumnBefore') }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addColumnAfter().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-plus-after\" /></template>\n <v-list-item-title>{{ t('TableAddColumnAfter') }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteColumn().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-remove\" /></template>\n <v-list-item-title>{{ t('TableDeleteColumn') }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().toggleHeaderRow().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row\" /></template>\n <v-list-item-title>{{ t('TableToggleHeaderRow') }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteTable().run()\">\n <template #prepend><cached-icon name=\"mdi-table-remove\" /></template>\n <v-list-item-title>{{ t('TableDeleteTable') }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n :title=\"t('Blockquote')\"\n :active=\"state.blockquote\"\n @click=\"editor?.chain().focus().toggleBlockquote().run()\"\n >\n <cached-icon name=\"mdi-format-quote-close\" />\n </v-btn>\n </div>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"alignActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"listActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Action, ExecuteAction } from '@dynamicforms/vue-forms';\nimport { Editor } from '@tiptap/vue-3';\nimport { isEqual } from 'lodash-es';\nimport { computed, ref, watchEffect } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport DfActions from '../../df-actions.vue';\nimport { ActionRenderOptions } from '../action';\nimport { VuetifyButtonSize } from '../input-base';\nimport { translate } from '../translations';\n\nimport { applyStyle, isStyleActive, STYLE_DEFS } from './block-styles';\nimport { fileToDataUrl } from './image-paste';\nimport { toEmbedSrc } from './media-embed';\nimport { useEditorTick } from './use-editor-tick';\n\nconst props = withDefaults(defineProps<{ editor?: Editor; buttonSize?: VuetifyButtonSize }>(), {\n editor: undefined,\n buttonSize: 'small',\n});\n\nconst buttonSize = computed(() => props.buttonSize);\n\nconst t = translate;\n\nconst editor = computed(() => props.editor);\nconst tick = useEditorTick(editor);\nconst editable = computed(() => {\n void tick.value;\n return !!props.editor?.isEditable;\n});\n\n// Shared across every standalone `<v-btn>`/`<df-actions>` in this toolbar, so a call site states only what\n// actually varies between buttons (icon, title, active/click handler) rather than repeating this on each one.\nconst toolbarButtonProps = computed(() => ({\n size: buttonSize.value,\n density: 'comfortable' as const,\n variant: 'text' as const,\n disabled: !editable.value,\n}));\nconst dfActionsProps = computed(() => ({ buttonSize: buttonSize.value, buttonDensity: 'comfortable' as const }));\n\nconst state = computed(() => {\n void tick.value;\n const e = props.editor;\n return {\n canUndo: !!e?.can().undo(),\n canRedo: !!e?.can().redo(),\n bold: !!e?.isActive('bold'),\n italic: !!e?.isActive('italic'),\n link: !!e?.isActive('link'),\n blockquote: !!e?.isActive('blockquote'),\n bulletList: !!e?.isActive('bulletList'),\n orderedList: !!e?.isActive('orderedList'),\n alignLeft: !!e?.isActive({ textAlign: 'left' }),\n alignCenter: !!e?.isActive({ textAlign: 'center' }),\n alignRight: !!e?.isActive({ textAlign: 'right' }),\n alignJustify: !!e?.isActive({ textAlign: 'justify' }),\n inTable: !!e?.isActive('table'),\n canLift: !!e?.can().liftListItem('listItem'),\n canSink: !!e?.can().sinkListItem('listItem'),\n };\n});\n\nconst alignValue = computed(() => {\n if (state.value.alignLeft) return 'left';\n if (state.value.alignCenter) return 'center';\n if (state.value.alignRight) return 'right';\n if (state.value.alignJustify) return 'justify';\n return undefined;\n});\n\nfunction setAlign(value: unknown) {\n if (typeof value !== 'string') return;\n editor.value?.chain().focus().setTextAlign(value).run();\n}\n\ninterface ToolbarActionSync {\n action: Action<ActionRenderOptions>;\n title: () => string;\n disabled: () => boolean;\n active?: () => boolean;\n}\n\nconst toolbarActionSyncs: ToolbarActionSync[] = [];\n\n// Static button clusters rendered through `<df-actions>` rather than `<v-btn-group>`/`<v-btn-toggle>`: each\n// button is a self-contained `Action`, so its look (size, rounded corners, active/disabled state) is drawn\n// from its own value rather than from props a parent component may or may not forward to it.\n//\n// `title`/`disabled`/`active` are getters, not one-off values, because an `Action`'s `value`/`enabled` are plain\n// assignments rather than bindings to a computed - the `watchEffect` below re-runs them on every reactive change\n// and writes the result into the action it was registered against.\nfunction toolbarAction(\n icon: string,\n onClick: () => void,\n title: () => string,\n disabled: () => boolean,\n active?: () => boolean,\n): Action<ActionRenderOptions> {\n const action = new Action<ActionRenderOptions>({\n value: { icon, renderAs: 'text', showIcon: true, showLabel: false },\n actions: [\n new ExecuteAction((a, supr, params) => {\n onClick();\n return supr(a, params);\n }),\n ],\n });\n toolbarActionSyncs.push({ action, title, disabled, active });\n return action;\n}\n\nfunction syncToolbarAction({ action, title, disabled, active }: ToolbarActionSync) {\n const wantAttrs: Record<string, unknown> = { title: title(), icon: true };\n if (active) wantAttrs.active = active();\n if (!isEqual(action.value.passthroughAttrs ?? {}, wantAttrs)) {\n action.value = { ...action.value, passthroughAttrs: wantAttrs };\n }\n\n const wantEnabled = !disabled();\n if (action.enabled !== wantEnabled) action.access = wantEnabled ? 'editable' : 'disabled';\n}\n\nconst undoRedoActions = [\n toolbarAction(\n 'mdi-undo',\n () => editor.value?.chain().focus().undo().run(),\n () => t('Undo'),\n () => !editable.value || !state.value.canUndo,\n ),\n toolbarAction(\n 'mdi-redo',\n () => editor.value?.chain().focus().redo().run(),\n () => t('Redo'),\n () => !editable.value || !state.value.canRedo,\n ),\n];\n\nconst boldItalicActions = [\n toolbarAction(\n 'mdi-format-bold',\n () => editor.value?.chain().focus().toggleBold().run(),\n () => t('Bold'),\n () => !editable.value,\n () => state.value.bold,\n ),\n toolbarAction(\n 'mdi-format-italic',\n () => editor.value?.chain().focus().toggleItalic().run(),\n () => t('Italic'),\n () => !editable.value,\n () => state.value.italic,\n ),\n];\n\nconst ALIGN_DEFS: { value: string; icon: string; title: () => string }[] = [\n { value: 'left', icon: 'mdi-format-align-left', title: () => t('AlignLeft') },\n { value: 'center', icon: 'mdi-format-align-center', title: () => t('AlignCenter') },\n { value: 'right', icon: 'mdi-format-align-right', title: () => t('AlignRight') },\n { value: 'justify', icon: 'mdi-format-align-justify', title: () => t('AlignJustify') },\n];\nconst alignActions = ALIGN_DEFS.map((def) =>\n toolbarAction(\n def.icon,\n () => setAlign(def.value),\n def.title,\n () => !editable.value,\n () => alignValue.value === def.value,\n ),\n);\n\nconst listActions = [\n toolbarAction(\n 'mdi-format-list-bulleted',\n () => editor.value?.chain().focus().toggleBulletList().run(),\n () => t('BulletedList'),\n () => !editable.value,\n () => state.value.bulletList,\n ),\n toolbarAction(\n 'mdi-format-list-numbered',\n () => editor.value?.chain().focus().toggleOrderedList().run(),\n () => t('NumberedList'),\n () => !editable.value,\n () => state.value.orderedList,\n ),\n toolbarAction(\n 'mdi-format-indent-decrease',\n () => editor.value?.chain().focus().liftListItem('listItem').run(),\n () => t('Outdent'),\n () => !editable.value || !state.value.canLift,\n ),\n toolbarAction(\n 'mdi-format-indent-increase',\n () => editor.value?.chain().focus().sinkListItem('listItem').run(),\n () => t('Indent'),\n () => !editable.value || !state.value.canSink,\n ),\n];\n\nwatchEffect(() => {\n toolbarActionSyncs.forEach(syncToolbarAction);\n});\n\nconst headingOptions = computed(\n () =>\n [\n { level: 0, label: t('Paragraph') },\n { level: 1, label: t('Heading1') },\n { level: 2, label: t('Heading2') },\n { level: 3, label: t('Heading3') },\n { level: 4, label: t('Heading4') },\n { level: 5, label: t('Heading5') },\n { level: 6, label: t('Heading6') },\n ] as const,\n);\n\nfunction isHeadingActive(level: number) {\n void tick.value;\n if (level === 0) return !!editor.value?.isActive('paragraph');\n return !!editor.value?.isActive('heading', { level });\n}\nconst headingLabel = computed(\n () => headingOptions.value.find((option) => isHeadingActive(option.level))?.label ?? t('Paragraph'),\n);\n\nfunction setHeading(level: number) {\n const chain = editor.value?.chain().focus();\n if (!chain) return;\n if (level === 0) chain.setParagraph().run();\n else chain.toggleHeading({ level: level as 1 | 2 | 3 | 4 | 5 | 6 }).run();\n}\n\n// Style dropdown\nconst styleDefs = STYLE_DEFS;\nfunction styleActive(def: (typeof STYLE_DEFS)[number]) {\n void tick.value;\n return !!editor.value && isStyleActive(editor.value, def);\n}\n\n// Link menu\nconst linkUrl = ref('');\nconst linkDownloadable = ref(false);\nfunction openLinkMenu() {\n const attrs = editor.value?.getAttributes('link') ?? {};\n linkUrl.value = attrs.href ?? '';\n linkDownloadable.value = !!attrs.download;\n}\nfunction applyLink() {\n if (!linkUrl.value) return;\n editor.value\n ?.chain()\n .focus()\n .extendMarkRange('link')\n .setLink({ href: linkUrl.value })\n .updateAttributes('link', { download: linkDownloadable.value ? 'file' : null })\n .run();\n}\nfunction removeLink() {\n editor.value?.chain().focus().unsetLink().run();\n}\n\n// Image menu\nconst imageUrl = ref('');\nconst imageInput = ref<HTMLInputElement>();\nfunction insertImageFromUrl() {\n if (!imageUrl.value) return;\n editor.value?.chain().focus().setImage({ src: imageUrl.value }).run();\n imageUrl.value = '';\n}\nfunction triggerImageUpload() {\n imageInput.value?.click();\n}\nasync function onImageFileChosen(event: Event) {\n const file = (event.target as HTMLInputElement).files?.[0];\n if (!file) return;\n const src = await fileToDataUrl(file);\n editor.value?.chain().focus().setImage({ src }).run();\n (event.target as HTMLInputElement).value = '';\n}\n\n// Media embed menu\nconst embedUrl = ref('');\nfunction insertMediaEmbed() {\n if (!embedUrl.value) return;\n const src = toEmbedSrc(embedUrl.value);\n const chain = editor.value?.chain().focus();\n if (!chain) return;\n if (src) chain.insertContent({ type: 'mediaEmbed', attrs: { src } }).run();\n else {\n chain\n .insertContent({ type: 'text', text: embedUrl.value, marks: [{ type: 'link', attrs: { href: embedUrl.value } }] })\n .run();\n }\n embedUrl.value = '';\n}\n</script>\n\n<style>\n.rtf-toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 2px;\n padding: 4px;\n overflow-x: auto;\n border-bottom: 1px solid rgb(var(--v-theme-surface-variant));\n}\n\n.rtf-toolbar--disabled {\n opacity: 0.6;\n}\n\n/* Mirrors `<df-actions>`'s own `button-group` look for the one cluster it can't render (it has no slot for a\n `v-menu` activator): a plain flex row rather than Vuetify's `v-btn-group`, whose child buttons are sized by a\n different formula than a standalone (or `<df-actions>`-rendered) icon button of the same `size`. */\n.rtf-toolbar-group {\n display: flex;\n}\n\n.rtf-toolbar-group .v-btn {\n border-radius: 0;\n}\n\n.rtf-toolbar-group .v-btn:first-child {\n border-start-start-radius: 0.5em;\n border-end-start-radius: 0.5em;\n}\n\n.rtf-toolbar-group .v-btn:last-child {\n border-start-end-radius: 0.5em;\n border-end-end-radius: 0.5em;\n}\n</style>\n","<template>\n <div class=\"rtf-toolbar\" :class=\"{ 'rtf-toolbar--disabled': !editable }\">\n <df-actions :actions=\"undoRedoActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n rounded=\"sm\"\n :title=\"t('SelectAll')\"\n @click=\"editor?.chain().focus().selectAll().run()\"\n >\n <cached-icon name=\"mdi-select-all\" />\n </v-btn>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" append-icon=\"mdi-chevron-down\">\n {{ headingLabel }}\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item\n v-for=\"option in headingOptions\"\n :key=\"option.level\"\n :active=\"isHeadingActive(option.level)\"\n @click=\"setHeading(option.level)\"\n >\n <v-list-item-title>{{ option.label }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" append-icon=\"mdi-chevron-down\">\n {{ t('Style') }}\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item\n v-for=\"def in styleDefs\"\n :key=\"def.key\"\n :active=\"styleActive(def)\"\n @click=\"editor && applyStyle(editor, def)\"\n >\n <v-list-item-title>{{ t(def.key) }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"boldItalicActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <div class=\"rtf-toolbar-group\">\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n :title=\"t('HorizontalLine')\"\n @click=\"editor?.chain().focus().setHorizontalRule().run()\"\n >\n <cached-icon name=\"mdi-minus\" />\n </v-btn>\n\n <v-menu :close-on-content-click=\"false\" @update:model-value=\"(shown: boolean) => shown && openLinkMenu()\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t('Link')\" :active=\"state.link\">\n <cached-icon name=\"mdi-link-variant\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"linkUrl\"\n :label=\"t('LinkUrl')\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"applyLink\"\n />\n <v-checkbox\n v-model=\"linkDownloadable\"\n :label=\"t('Downloadable')\"\n density=\"compact\"\n hide-details\n class=\"mt-1\"\n />\n <div class=\"d-flex justify-end ga-2 mt-2\">\n <v-btn v-if=\"state.link\" size=\"small\" variant=\"text\" @click=\"removeLink\">{{ t('LinkRemove') }}</v-btn>\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"applyLink\">{{ t('LinkApply') }}</v-btn>\n </div>\n </v-card>\n </v-menu>\n\n <v-menu :close-on-content-click=\"false\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t('Image')\">\n <cached-icon name=\"mdi-image-plus\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"imageUrl\"\n :label=\"t('ImageUrl')\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"insertImageFromUrl\"\n />\n <div class=\"d-flex justify-space-between align-center ga-2 mt-2\">\n <v-btn size=\"small\" variant=\"text\" prepend-icon=\"mdi-upload\" @click=\"triggerImageUpload\">\n {{ t('ImageUpload') }}\n </v-btn>\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"insertImageFromUrl\">\n {{ t('ImageInsert') }}\n </v-btn>\n </div>\n </v-card>\n </v-menu>\n <input ref=\"imageInput\" type=\"file\" accept=\"image/*\" class=\"d-none\" @change=\"onImageFileChosen\" />\n\n <v-menu :close-on-content-click=\"false\">\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t('MediaEmbed')\">\n <cached-icon name=\"mdi-video-plus\" />\n </v-btn>\n </template>\n <v-card min-width=\"280\" class=\"pa-3\">\n <v-text-field\n v-model=\"embedUrl\"\n :label=\"t('MediaEmbedUrl')\"\n density=\"compact\"\n hide-details\n autofocus\n @keydown.enter=\"insertMediaEmbed\"\n />\n <div class=\"d-flex justify-end mt-2\">\n <v-btn size=\"small\" color=\"primary\" variant=\"tonal\" @click=\"insertMediaEmbed\">\n {{ t('MediaEmbedInsert') }}\n </v-btn>\n </div>\n </v-card>\n </v-menu>\n\n <v-menu>\n <template #activator=\"{ props: menuProps }\">\n <v-btn v-bind=\"{ ...toolbarButtonProps, ...menuProps }\" icon :title=\"t('Table')\">\n <cached-icon name=\"mdi-table\" />\n </v-btn>\n </template>\n <v-list density=\"compact\">\n <v-list-item @click=\"editor?.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()\">\n <template #prepend><cached-icon name=\"mdi-table-plus\" /></template>\n <v-list-item-title>{{ t('TableInsert') }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addRowBefore().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-plus-before\" /></template>\n <v-list-item-title>{{ t('TableAddRowAbove') }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addRowAfter().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-plus-after\" /></template>\n <v-list-item-title>{{ t('TableAddRowBelow') }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteRow().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row-remove\" /></template>\n <v-list-item-title>{{ t('TableDeleteRow') }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addColumnBefore().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-plus-before\" /></template>\n <v-list-item-title>{{ t('TableAddColumnBefore') }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().addColumnAfter().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-plus-after\" /></template>\n <v-list-item-title>{{ t('TableAddColumnAfter') }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteColumn().run()\">\n <template #prepend><cached-icon name=\"mdi-table-column-remove\" /></template>\n <v-list-item-title>{{ t('TableDeleteColumn') }}</v-list-item-title>\n </v-list-item>\n <v-divider />\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().toggleHeaderRow().run()\">\n <template #prepend><cached-icon name=\"mdi-table-row\" /></template>\n <v-list-item-title>{{ t('TableToggleHeaderRow') }}</v-list-item-title>\n </v-list-item>\n <v-list-item :disabled=\"!state.inTable\" @click=\"editor?.chain().focus().deleteTable().run()\">\n <template #prepend><cached-icon name=\"mdi-table-remove\" /></template>\n <v-list-item-title>{{ t('TableDeleteTable') }}</v-list-item-title>\n </v-list-item>\n </v-list>\n </v-menu>\n\n <v-btn\n v-bind=\"toolbarButtonProps\"\n icon\n :title=\"t('Blockquote')\"\n :active=\"state.blockquote\"\n @click=\"editor?.chain().focus().toggleBlockquote().run()\"\n >\n <cached-icon name=\"mdi-format-quote-close\" />\n </v-btn>\n </div>\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"alignActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n\n <v-divider vertical inset class=\"mx-1\" />\n\n <df-actions :actions=\"listActions\" v-bind=\"dfActionsProps\" show-as-group=\"grouped-no-borders\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Action, ExecuteAction } from '@dynamicforms/vue-forms';\nimport { Editor } from '@tiptap/vue-3';\nimport { isEqual } from 'lodash-es';\nimport { computed, ref, watchEffect } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport DfActions from '../../df-actions.vue';\nimport { ActionRenderOptions } from '../action';\nimport { VuetifyButtonSize } from '../input-base';\nimport { translate } from '../translations';\n\nimport { applyStyle, isStyleActive, STYLE_DEFS } from './block-styles';\nimport { fileToDataUrl } from './image-paste';\nimport { toEmbedSrc } from './media-embed';\nimport { useEditorTick } from './use-editor-tick';\n\nconst props = withDefaults(defineProps<{ editor?: Editor; buttonSize?: VuetifyButtonSize }>(), {\n editor: undefined,\n buttonSize: 'small',\n});\n\nconst buttonSize = computed(() => props.buttonSize);\n\nconst t = translate;\n\nconst editor = computed(() => props.editor);\nconst tick = useEditorTick(editor);\nconst editable = computed(() => {\n void tick.value;\n return !!props.editor?.isEditable;\n});\n\n// Shared across every standalone `<v-btn>`/`<df-actions>` in this toolbar, so a call site states only what\n// actually varies between buttons (icon, title, active/click handler) rather than repeating this on each one.\nconst toolbarButtonProps = computed(() => ({\n size: buttonSize.value,\n density: 'comfortable' as const,\n variant: 'text' as const,\n disabled: !editable.value,\n}));\nconst dfActionsProps = computed(() => ({ buttonSize: buttonSize.value, buttonDensity: 'comfortable' as const }));\n\nconst state = computed(() => {\n void tick.value;\n const e = props.editor;\n return {\n canUndo: !!e?.can().undo(),\n canRedo: !!e?.can().redo(),\n bold: !!e?.isActive('bold'),\n italic: !!e?.isActive('italic'),\n link: !!e?.isActive('link'),\n blockquote: !!e?.isActive('blockquote'),\n bulletList: !!e?.isActive('bulletList'),\n orderedList: !!e?.isActive('orderedList'),\n alignLeft: !!e?.isActive({ textAlign: 'left' }),\n alignCenter: !!e?.isActive({ textAlign: 'center' }),\n alignRight: !!e?.isActive({ textAlign: 'right' }),\n alignJustify: !!e?.isActive({ textAlign: 'justify' }),\n inTable: !!e?.isActive('table'),\n canLift: !!e?.can().liftListItem('listItem'),\n canSink: !!e?.can().sinkListItem('listItem'),\n };\n});\n\nconst alignValue = computed(() => {\n if (state.value.alignLeft) return 'left';\n if (state.value.alignCenter) return 'center';\n if (state.value.alignRight) return 'right';\n if (state.value.alignJustify) return 'justify';\n return undefined;\n});\n\nfunction setAlign(value: unknown) {\n if (typeof value !== 'string') return;\n editor.value?.chain().focus().setTextAlign(value).run();\n}\n\ninterface ToolbarActionSync {\n action: Action<ActionRenderOptions>;\n title: () => string;\n disabled: () => boolean;\n active?: () => boolean;\n}\n\nconst toolbarActionSyncs: ToolbarActionSync[] = [];\n\n// Static button clusters rendered through `<df-actions>` rather than `<v-btn-group>`/`<v-btn-toggle>`: each\n// button is a self-contained `Action`, so its look (size, rounded corners, active/disabled state) is drawn\n// from its own value rather than from props a parent component may or may not forward to it.\n//\n// `title`/`disabled`/`active` are getters, not one-off values, because an `Action`'s `value`/`enabled` are plain\n// assignments rather than bindings to a computed - the `watchEffect` below re-runs them on every reactive change\n// and writes the result into the action it was registered against.\nfunction toolbarAction(\n icon: string,\n onClick: () => void,\n title: () => string,\n disabled: () => boolean,\n active?: () => boolean,\n): Action<ActionRenderOptions> {\n const action = new Action<ActionRenderOptions>({\n value: { icon, renderAs: 'text', showIcon: true, showLabel: false },\n actions: [\n new ExecuteAction((a, supr, params) => {\n onClick();\n return supr(a, params);\n }),\n ],\n });\n toolbarActionSyncs.push({ action, title, disabled, active });\n return action;\n}\n\nfunction syncToolbarAction({ action, title, disabled, active }: ToolbarActionSync) {\n const wantAttrs: Record<string, unknown> = { title: title(), icon: true };\n if (active) wantAttrs.active = active();\n if (!isEqual(action.value.passthroughAttrs ?? {}, wantAttrs)) {\n action.value = { ...action.value, passthroughAttrs: wantAttrs };\n }\n\n const wantEnabled = !disabled();\n if (action.enabled !== wantEnabled) action.access = wantEnabled ? 'editable' : 'disabled';\n}\n\nconst undoRedoActions = [\n toolbarAction(\n 'mdi-undo',\n () => editor.value?.chain().focus().undo().run(),\n () => t('Undo'),\n () => !editable.value || !state.value.canUndo,\n ),\n toolbarAction(\n 'mdi-redo',\n () => editor.value?.chain().focus().redo().run(),\n () => t('Redo'),\n () => !editable.value || !state.value.canRedo,\n ),\n];\n\nconst boldItalicActions = [\n toolbarAction(\n 'mdi-format-bold',\n () => editor.value?.chain().focus().toggleBold().run(),\n () => t('Bold'),\n () => !editable.value,\n () => state.value.bold,\n ),\n toolbarAction(\n 'mdi-format-italic',\n () => editor.value?.chain().focus().toggleItalic().run(),\n () => t('Italic'),\n () => !editable.value,\n () => state.value.italic,\n ),\n];\n\nconst ALIGN_DEFS: { value: string; icon: string; title: () => string }[] = [\n { value: 'left', icon: 'mdi-format-align-left', title: () => t('AlignLeft') },\n { value: 'center', icon: 'mdi-format-align-center', title: () => t('AlignCenter') },\n { value: 'right', icon: 'mdi-format-align-right', title: () => t('AlignRight') },\n { value: 'justify', icon: 'mdi-format-align-justify', title: () => t('AlignJustify') },\n];\nconst alignActions = ALIGN_DEFS.map((def) =>\n toolbarAction(\n def.icon,\n () => setAlign(def.value),\n def.title,\n () => !editable.value,\n () => alignValue.value === def.value,\n ),\n);\n\nconst listActions = [\n toolbarAction(\n 'mdi-format-list-bulleted',\n () => editor.value?.chain().focus().toggleBulletList().run(),\n () => t('BulletedList'),\n () => !editable.value,\n () => state.value.bulletList,\n ),\n toolbarAction(\n 'mdi-format-list-numbered',\n () => editor.value?.chain().focus().toggleOrderedList().run(),\n () => t('NumberedList'),\n () => !editable.value,\n () => state.value.orderedList,\n ),\n toolbarAction(\n 'mdi-format-indent-decrease',\n () => editor.value?.chain().focus().liftListItem('listItem').run(),\n () => t('Outdent'),\n () => !editable.value || !state.value.canLift,\n ),\n toolbarAction(\n 'mdi-format-indent-increase',\n () => editor.value?.chain().focus().sinkListItem('listItem').run(),\n () => t('Indent'),\n () => !editable.value || !state.value.canSink,\n ),\n];\n\nwatchEffect(() => {\n toolbarActionSyncs.forEach(syncToolbarAction);\n});\n\nconst headingOptions = computed(\n () =>\n [\n { level: 0, label: t('Paragraph') },\n { level: 1, label: t('Heading1') },\n { level: 2, label: t('Heading2') },\n { level: 3, label: t('Heading3') },\n { level: 4, label: t('Heading4') },\n { level: 5, label: t('Heading5') },\n { level: 6, label: t('Heading6') },\n ] as const,\n);\n\nfunction isHeadingActive(level: number) {\n void tick.value;\n if (level === 0) return !!editor.value?.isActive('paragraph');\n return !!editor.value?.isActive('heading', { level });\n}\nconst headingLabel = computed(\n () => headingOptions.value.find((option) => isHeadingActive(option.level))?.label ?? t('Paragraph'),\n);\n\nfunction setHeading(level: number) {\n const chain = editor.value?.chain().focus();\n if (!chain) return;\n if (level === 0) chain.setParagraph().run();\n else chain.toggleHeading({ level: level as 1 | 2 | 3 | 4 | 5 | 6 }).run();\n}\n\n// Style dropdown\nconst styleDefs = STYLE_DEFS;\nfunction styleActive(def: (typeof STYLE_DEFS)[number]) {\n void tick.value;\n return !!editor.value && isStyleActive(editor.value, def);\n}\n\n// Link menu\nconst linkUrl = ref('');\nconst linkDownloadable = ref(false);\nfunction openLinkMenu() {\n const attrs = editor.value?.getAttributes('link') ?? {};\n linkUrl.value = attrs.href ?? '';\n linkDownloadable.value = !!attrs.download;\n}\nfunction applyLink() {\n if (!linkUrl.value) return;\n editor.value\n ?.chain()\n .focus()\n .extendMarkRange('link')\n .setLink({ href: linkUrl.value })\n .updateAttributes('link', { download: linkDownloadable.value ? 'file' : null })\n .run();\n}\nfunction removeLink() {\n editor.value?.chain().focus().unsetLink().run();\n}\n\n// Image menu\nconst imageUrl = ref('');\nconst imageInput = ref<HTMLInputElement>();\nfunction insertImageFromUrl() {\n if (!imageUrl.value) return;\n editor.value?.chain().focus().setImage({ src: imageUrl.value }).run();\n imageUrl.value = '';\n}\nfunction triggerImageUpload() {\n imageInput.value?.click();\n}\nasync function onImageFileChosen(event: Event) {\n const file = (event.target as HTMLInputElement).files?.[0];\n if (!file) return;\n const src = await fileToDataUrl(file);\n editor.value?.chain().focus().setImage({ src }).run();\n (event.target as HTMLInputElement).value = '';\n}\n\n// Media embed menu\nconst embedUrl = ref('');\nfunction insertMediaEmbed() {\n if (!embedUrl.value) return;\n const src = toEmbedSrc(embedUrl.value);\n const chain = editor.value?.chain().focus();\n if (!chain) return;\n if (src) chain.insertContent({ type: 'mediaEmbed', attrs: { src } }).run();\n else {\n chain\n .insertContent({ type: 'text', text: embedUrl.value, marks: [{ type: 'link', attrs: { href: embedUrl.value } }] })\n .run();\n }\n embedUrl.value = '';\n}\n</script>\n\n<style>\n.rtf-toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 2px;\n padding: 4px;\n overflow-x: auto;\n border-bottom: 1px solid rgb(var(--v-theme-surface-variant));\n}\n\n.rtf-toolbar--disabled {\n opacity: 0.6;\n}\n\n/* Mirrors `<df-actions>`'s own `button-group` look for the one cluster it can't render (it has no slot for a\n `v-menu` activator): a plain flex row rather than Vuetify's `v-btn-group`, whose child buttons are sized by a\n different formula than a standalone (or `<df-actions>`-rendered) icon button of the same `size`. */\n.rtf-toolbar-group {\n display: flex;\n}\n\n.rtf-toolbar-group .v-btn {\n border-radius: 0;\n}\n\n.rtf-toolbar-group .v-btn:first-child {\n border-start-start-radius: 0.5em;\n border-end-start-radius: 0.5em;\n}\n\n.rtf-toolbar-group .v-btn:last-child {\n border-start-end-radius: 0.5em;\n border-end-end-radius: 0.5em;\n}\n</style>\n","// Content copied from Word or Google Docs carries mso-* inline styles, Mso*-prefixed classes, namespaced tags\n// (o:p, w:sdt, v:shape...), and conditional-compilation comments that are meaningless outside their originating\n// document. Left in place, they either render as visible clutter or silently defeat the mark/heading detection\n// the editor's own paste parsing relies on (an inline `mso-bidi-font-weight` next to a real `font-weight:bold`\n// is harmless, but a class name colliding with one this library uses for content styling would not be).\nconst NAMESPACED_TAG = /^[a-z][a-z0-9]*:[a-z]/i;\nconst MSO_STYLE_PROPERTY = /mso-[a-z-]+\\s*:[^;]+;?/gi;\nconst MSO_CLASS = /^Mso/i;\n// Word's own cell/table shading (Automatic/theme colours resolved at copy time, not necessarily what the\n// document visibly showed) rides along as a plain, non-mso `background`/`background-color` - stripped so a\n// pasted table adopts the editor's own theme instead of carrying the source document's shading. Foreground\n// `color` is left alone: unlike background shading, it is usually deliberate content styling worth keeping.\nconst BACKGROUND_STYLE_PROPERTY = /background(?:-color)?\\s*:[^;]+;?/gi;\n\nfunction stripComments(root: Element) {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n const comments: Comment[] = [];\n for (let node = walker.nextNode(); node; node = walker.nextNode()) comments.push(node as Comment);\n comments.forEach((comment) => comment.parentNode?.removeChild(comment));\n}\n\nfunction unwrap(element: Element) {\n const parent = element.parentNode;\n if (!parent) return;\n while (element.firstChild) parent.insertBefore(element.firstChild, element);\n parent.removeChild(element);\n}\n\nfunction cleanAttributes(element: HTMLElement) {\n const style = element.getAttribute('style');\n if (style != null) {\n const cleaned = style.replace(MSO_STYLE_PROPERTY, '').replace(BACKGROUND_STYLE_PROPERTY, '').trim();\n if (cleaned) element.setAttribute('style', cleaned);\n else element.removeAttribute('style');\n }\n\n const cssClass = element.getAttribute('class');\n if (cssClass != null) {\n const cleaned = cssClass\n .split(/\\s+/)\n .filter((name) => name && !MSO_CLASS.test(name))\n .join(' ');\n if (cleaned) element.setAttribute('class', cleaned);\n else element.removeAttribute('class');\n }\n\n element.removeAttribute('lang');\n element.removeAttribute('xml:lang');\n element.removeAttribute('id');\n element.removeAttribute('align');\n element.removeAttribute('bgcolor');\n}\n\n/**\n * Strips Word/Google Docs clipboard artifacts from pasted HTML before it reaches the editor's schema parser:\n * conditional comments, `<xml>`/`<style>`/`<meta>` blocks, namespaced tags (`o:p`, `w:sdt`, `v:shape`...),\n * `mso-*` inline style properties, `Mso*` classes, `background`/`background-color`/`bgcolor` shading, and\n * `lang`/`id`/`align` attributes. Real formatting left behind (`font-weight`, `<b>`, `<table>`, `<h1>`...) is\n * untouched, since it is what the editor's own extensions parse into marks, headings, lists and tables.\n */\nexport function stripWordArtifacts(html: string): string {\n if (!html || typeof DOMParser === 'undefined') return html;\n\n const doc = new DOMParser().parseFromString(html, 'text/html');\n const root = doc.body;\n if (!root) return html;\n\n stripComments(root);\n root.querySelectorAll('xml, style, script, meta, link').forEach((node) => node.remove());\n\n Array.from(root.querySelectorAll<HTMLElement>('*')).forEach((element) => {\n if (NAMESPACED_TAG.test(element.tagName) || element.tagName === 'FONT') {\n unwrap(element);\n return;\n }\n cleanAttributes(element);\n });\n\n // A span or div left with no attributes after cleanup is a pure wrapper Word adds around every run of text.\n Array.from(root.querySelectorAll('span, div')).forEach((element) => {\n if (element.attributes.length === 0) unwrap(element);\n });\n\n return root.innerHTML;\n}\n","<template>\n <div class=\"editor-container\">\n <rtf-toolbar v-if=\"clientRendered\" :ref=\"setToolbar\" :editor=\"editor\" :button-size=\"toolbarButtonSize\" />\n <editor-content v-if=\"clientRendered\" class=\"editor-container__editor\" :editor=\"editor\" />\n <!-- on the server, and until it renders in the browser, the value's text -->\n <div v-else class=\"editor-container__editor\">{{ valueText }}</div>\n <bubble-menu v-if=\"editor\" :editor=\"editor\" :should-show=\"bubbleShouldShow\">\n <div class=\"rtf-bubble-menu\">\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.bold\" @click=\"toggle('toggleBold')\">\n <cached-icon name=\"mdi-format-bold\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.italic\" @click=\"toggle('toggleItalic')\">\n <cached-icon name=\"mdi-format-italic\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.link\" @click=\"toggleBubbleLink\">\n <cached-icon name=\"mdi-link-variant\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.bulletList\" @click=\"toggle('toggleBulletList')\">\n <cached-icon name=\"mdi-format-list-bulleted\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.orderedList\" @click=\"toggle('toggleOrderedList')\">\n <cached-icon name=\"mdi-format-list-numbered\" />\n </v-btn>\n </div>\n </bubble-menu>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Image from '@tiptap/extension-image';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { Table } from '@tiptap/extension-table';\nimport TableCell from '@tiptap/extension-table-cell';\nimport TableHeader from '@tiptap/extension-table-header';\nimport TableRow from '@tiptap/extension-table-row';\nimport TextAlign from '@tiptap/extension-text-align';\nimport { NodeSelection } from '@tiptap/pm/state';\nimport StarterKit from '@tiptap/starter-kit';\nimport { EditorContent, useEditor } from '@tiptap/vue-3';\nimport { BubbleMenu } from '@tiptap/vue-3/menus';\nimport { type ComponentPublicInstance, computed, onBeforeUnmount, ref, watch } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { useClientRendered } from '../client-rendered';\nimport { VuetifyButtonSize } from '../input-base';\nimport { HtmlString, renderContentText } from '../render-content';\nimport { useTranslate } from '../translations';\n\nimport { ClassAttribute, Marker, Spoiler } from './block-styles';\nimport { createImagePasteHandler } from './image-paste';\nimport { LinkWithDownload } from './link-with-download';\nimport { MediaEmbed } from './media-embed';\nimport RtfToolbar from './rtf-toolbar.vue';\nimport { useEditorTick } from './use-editor-tick';\nimport { stripWordArtifacts } from './word-paste';\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string;\n minHeight?: string;\n disabled?: boolean;\n toolbarButtonSize?: VuetifyButtonSize;\n fontFamily?: string;\n }>(),\n { modelValue: '', minHeight: '7em', disabled: false, toolbarButtonSize: 'small', fontFamily: 'inherit' },\n);\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void;\n}>();\n\n// `<df-rtf-editor>`'s label is positioned by a fixed `translate()` in its own stylesheet, tuned around a\n// single-row toolbar - it has no other way to know the toolbar's actual height, since the label (drawn by\n// `v-field`'s `#label` slot) and the toolbar (drawn by this component, inside `v-field`'s default slot) are\n// siblings, not ancestor/descendant. Publishing the toolbar's measured height as a CSS custom property on their\n// shared `.v-field` ancestor lets that `translate()` read a real value instead of guessing one - it still needs\n// to reach up past this component's own root to a DOM node it doesn't otherwise touch, which is what the\n// `.closest()` below is for.\n// a function ref: a template ref by name would put the toolbar's types into the declarations this component emits\nconst toolbarRef = ref<ComponentPublicInstance | null>(null);\nfunction setToolbar(el: unknown) {\n toolbarRef.value = el as ComponentPublicInstance | null;\n}\nconst clientRendered = useClientRendered();\nconst valueText = computed(() => renderContentText(new HtmlString(props.modelValue ?? '')));\nconst t = useTranslate();\nlet toolbarResizeObserver: ResizeObserver | undefined;\n\n// the toolbar is rendered once the component renders in the browser, at mount or after it\nwatch(\n toolbarRef,\n (toolbar) => {\n toolbarResizeObserver?.disconnect();\n const toolbarEl = toolbar?.$el as HTMLElement | undefined;\n const fieldEl = toolbarEl?.closest<HTMLElement>('.v-field');\n if (!toolbarEl || !fieldEl) return;\n toolbarResizeObserver = new ResizeObserver(([entry]) => {\n fieldEl.style.setProperty('--rtf-toolbar-height', `${entry.contentRect.height}px`);\n });\n toolbarResizeObserver.observe(toolbarEl);\n },\n { flush: 'post' },\n);\nonBeforeUnmount(() => toolbarResizeObserver?.disconnect());\n\nconst editor = useEditor({\n content: props.modelValue,\n editable: !props.disabled,\n extensions: [\n StarterKit.configure({ link: false }),\n LinkWithDownload.configure({ openOnClick: false, autolink: true, defaultProtocol: 'https' }),\n Image.configure({\n inline: true,\n allowBase64: true,\n resize: {\n enabled: true,\n directions: ['top', 'right', 'bottom', 'left', 'top-left', 'top-right', 'bottom-left', 'bottom-right'],\n minWidth: 24,\n minHeight: 24,\n },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Table.configure({ resizable: true }),\n TableRow,\n TableHeader,\n TableCell,\n Placeholder.configure({ placeholder: '' }),\n ClassAttribute,\n Marker,\n Spoiler,\n MediaEmbed,\n ],\n editorProps: {\n attributes: { class: 'rtf-content' },\n transformPastedHTML: (html: string) => stripWordArtifacts(html),\n handlePaste: createImagePasteHandler(() => editor.value),\n },\n // ProseMirror's schema never lets the document itself be empty - a cleared editor still holds one empty\n // paragraph, whose serialized HTML is '<p></p>'. Emitting that instead of '' would make a `required` rule\n // checking for a falsy modelValue pass on a field the user never actually typed or pasted anything into.\n onUpdate: ({ editor: instance }) => {\n emit('update:modelValue', instance.isEmpty ? '' : instance.getHTML());\n },\n});\n\n// External writes (a reset, a different record loaded into the same form) are applied without re-emitting: the\n// third `setContent` argument suppresses the `update` this would otherwise trigger straight back out.\nwatch(\n () => props.modelValue,\n (value) => {\n const instance = editor.value;\n if (!instance) return;\n const incoming = value ?? '';\n if (incoming === instance.getHTML()) return;\n instance.commands.setContent(incoming, { emitUpdate: false });\n },\n);\n\n// setEditable emits an `update` unless told not to: it would write the editor's serialization of the value, which\n// differs from the value as written (`<b>` read back as `<strong>`), into the field the user has not edited\nwatch(\n () => props.disabled,\n (disabled) => editor.value?.setEditable(!disabled, false),\n);\nwatch(editor, (instance) => instance?.setEditable(!props.disabled, false));\n\nconst bubbleButtonProps = { icon: true, size: 'small', density: 'comfortable', variant: 'text' } as const;\n\nconst bubbleTick = useEditorTick(editor);\nconst bubbleState = computed(() => {\n void bubbleTick.value;\n return {\n bold: !!editor.value?.isActive('bold'),\n italic: !!editor.value?.isActive('italic'),\n link: !!editor.value?.isActive('link'),\n bulletList: !!editor.value?.isActive('bulletList'),\n orderedList: !!editor.value?.isActive('orderedList'),\n };\n});\n\n// A NodeSelection (an image, a table, a horizontal rule - anything selected as a whole rather than as text) is\n// excluded: bold/italic/link/list toggles don't apply to a selected node, so showing this text-formatting bubble\n// over one is just noise sitting on top of whatever selection UI that node has of its own (an image's resize\n// handles, for instance).\nfunction bubbleShouldShow({ state }: { state: { selection: { empty: boolean } } }) {\n return !state.selection.empty && !(state.selection instanceof NodeSelection);\n}\n\nfunction toggle(command: 'toggleBold' | 'toggleItalic' | 'toggleBulletList' | 'toggleOrderedList') {\n editor.value?.chain().focus()[command]().run();\n}\n\nfunction toggleBubbleLink() {\n const instance = editor.value;\n if (!instance) return;\n if (instance.isActive('link')) {\n instance.chain().focus().unsetLink().run();\n return;\n }\n\n const href = window.prompt(t('LinkUrl'));\n if (href) instance.chain().focus().extendMarkRange('link').setLink({ href }).run();\n}\n</script>\n\n<style>\n@media print {\n body {\n margin: 0 !important;\n }\n}\n\n.editor-container {\n font-family: v-bind(fontFamily);\n width: 100%;\n}\n\n.rtf-content {\n line-height: 1.6;\n word-break: break-word;\n min-height: v-bind(minHeight);\n padding: 0.5em 0.75em;\n background: rgb(var(--v-theme-surface));\n color: rgb(var(--v-theme-on-surface));\n outline: none;\n}\n\n.rtf-content p {\n margin: 0 0 1em;\n}\n\n/* ProseMirror's list/table schemas wrap every block of text in a <p>, list item or cell content included, so\n without this every list item and table cell would carry the same margin ordinary paragraphs do - list items\n readable as double-spaced lines, cells with dead space above and below their text. */\n.rtf-content li p,\n.rtf-content td p,\n.rtf-content th p {\n margin: 0;\n}\n\n.rtf-content li + li {\n margin-top: 0;\n}\n\n.rtf-content img {\n max-width: 100%;\n height: auto;\n}\n\n/* TipTap's image resize NodeView (@tiptap/extension-image's `resize` option) builds the handle elements below\n with no visual styling of their own - position only - so the consuming app is expected to supply the look. */\n.rtf-content [data-resize-handle] {\n background: rgb(var(--v-theme-primary));\n border: 1px solid rgb(var(--v-theme-surface));\n border-radius: 2px;\n opacity: 0;\n transition: opacity 0.1s ease;\n z-index: 1;\n}\n\n.rtf-content [data-resize-container]:hover [data-resize-handle],\n.rtf-content [data-resize-container]:focus-within [data-resize-handle] {\n opacity: 1;\n}\n\n.rtf-content [data-resize-handle='top'],\n.rtf-content [data-resize-handle='bottom'] {\n height: 6px;\n cursor: ns-resize;\n}\n\n.rtf-content [data-resize-handle='left'],\n.rtf-content [data-resize-handle='right'] {\n width: 6px;\n cursor: ew-resize;\n}\n\n.rtf-content [data-resize-handle='top-left'],\n.rtf-content [data-resize-handle='bottom-right'] {\n width: 10px;\n height: 10px;\n cursor: nwse-resize;\n}\n\n.rtf-content [data-resize-handle='top-right'],\n.rtf-content [data-resize-handle='bottom-left'] {\n width: 10px;\n height: 10px;\n cursor: nesw-resize;\n}\n\n/* Holding Shift while dragging a handle locks the aspect ratio (ResizableNodeView's own behaviour, not\n something this component adds) - a one-off tooltip on the corner handle most people reach for first is enough\n to surface it, rather than a whole toolbar for a modifier key. */\n.rtf-content [data-resize-handle='bottom-right']:hover::after {\n content: 'Hold Shift to keep the aspect ratio';\n position: absolute;\n bottom: 14px;\n right: 0;\n white-space: nowrap;\n font-size: 12px;\n padding: 2px 6px;\n border-radius: 4px;\n background: rgb(var(--v-theme-surface-variant));\n color: rgb(var(--v-theme-on-surface-variant));\n pointer-events: none;\n}\n\n.rtf-content iframe.media-embed {\n width: 100%;\n aspect-ratio: 16 / 9;\n margin: 1em 0;\n border: 0;\n}\n\n.rtf-bubble-menu {\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 2px;\n background: rgb(var(--v-theme-surface));\n border: 1px solid rgb(var(--v-theme-surface-variant));\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n}\n\n.rtf-content h3.category {\n font-size: 20px;\n font-weight: bold;\n color: #555;\n letter-spacing: 10px;\n margin: 0;\n padding: 0;\n}\n\n.rtf-content h2.document-title {\n font-size: 50px;\n font-weight: bold;\n margin: 0;\n padding: 0;\n border: 0;\n}\n\n.rtf-content h3.document-subtitle {\n font-size: 20px;\n color: #555;\n margin: 0 0 1em;\n font-weight: bold;\n padding: 0;\n}\n\n.rtf-content p.info-box {\n --background-size: 30px;\n --background-color: #e91e63;\n padding: 1.2em 2em;\n border: 1px solid var(--background-color);\n background:\n linear-gradient(\n 135deg,\n var(--background-color) 0%,\n var(--background-color) var(--background-size),\n transparent var(--background-size)\n ),\n linear-gradient(\n 135deg,\n transparent calc(100% - var(--background-size)),\n var(--background-color) calc(100% - var(--background-size)),\n var(--background-color)\n );\n border-radius: 10px;\n margin: 1.5em 2em;\n box-shadow: 5px 5px 0 #ffe6ef;\n}\n\n.rtf-content blockquote.side-quote {\n font-style: normal;\n float: right;\n width: 35%;\n position: relative;\n border: 0;\n overflow: visible;\n z-index: 1;\n margin-left: 1em;\n}\n\n.rtf-content blockquote.side-quote::before {\n content: '“';\n position: absolute;\n top: -37px;\n left: -10px;\n display: block;\n font-size: 200px;\n color: #e7e7e7;\n z-index: -1;\n line-height: 1;\n}\n\n.rtf-content blockquote.side-quote p {\n font-size: 2em;\n line-height: 1;\n}\n\n.rtf-content blockquote.side-quote p:last-child:not(:first-child) {\n font-size: 1.3em;\n text-align: right;\n color: #555;\n}\n\n.rtf-content span.marker {\n background: yellow;\n}\n\n.rtf-content span.spoiler {\n background: #000;\n color: #000;\n}\n\n.rtf-content span.spoiler:hover {\n background: #000;\n color: #fff;\n}\n\n.rtf-content pre.fancy-code {\n border: 0;\n margin-left: 2em;\n margin-right: 2em;\n border-radius: 10px;\n}\n\n.rtf-content pre.fancy-code::before {\n content: '';\n display: block;\n height: 13px;\n background: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NCAxMyI+CiAgPGNpcmNsZSBjeD0iNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGMzZCNUMiLz4KICA8Y2lyY2xlIGN4PSIyNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGOUJFNEQiLz4KICA8Y2lyY2xlIGN4PSI0Ny41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiM1NkM0NTMiLz4KPC9zdmc+Cg==);\n margin-bottom: 8px;\n background-repeat: no-repeat;\n}\n\n.rtf-content pre.fancy-code-dark {\n background: #272822;\n color: #fff;\n box-shadow: 5px 5px 0 #0000001f;\n}\n\n.rtf-content pre.fancy-code-bright {\n background: #dddfe0;\n color: #000;\n box-shadow: 5px 5px 0 #b3b3b3;\n}\n</style>\n","<template>\n <div class=\"editor-container\">\n <rtf-toolbar v-if=\"clientRendered\" :ref=\"setToolbar\" :editor=\"editor\" :button-size=\"toolbarButtonSize\" />\n <editor-content v-if=\"clientRendered\" class=\"editor-container__editor\" :editor=\"editor\" />\n <!-- on the server, and until it renders in the browser, the value's text -->\n <div v-else class=\"editor-container__editor\">{{ valueText }}</div>\n <bubble-menu v-if=\"editor\" :editor=\"editor\" :should-show=\"bubbleShouldShow\">\n <div class=\"rtf-bubble-menu\">\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.bold\" @click=\"toggle('toggleBold')\">\n <cached-icon name=\"mdi-format-bold\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.italic\" @click=\"toggle('toggleItalic')\">\n <cached-icon name=\"mdi-format-italic\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.link\" @click=\"toggleBubbleLink\">\n <cached-icon name=\"mdi-link-variant\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.bulletList\" @click=\"toggle('toggleBulletList')\">\n <cached-icon name=\"mdi-format-list-bulleted\" />\n </v-btn>\n <v-btn v-bind=\"bubbleButtonProps\" :active=\"bubbleState.orderedList\" @click=\"toggle('toggleOrderedList')\">\n <cached-icon name=\"mdi-format-list-numbered\" />\n </v-btn>\n </div>\n </bubble-menu>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Image from '@tiptap/extension-image';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { Table } from '@tiptap/extension-table';\nimport TableCell from '@tiptap/extension-table-cell';\nimport TableHeader from '@tiptap/extension-table-header';\nimport TableRow from '@tiptap/extension-table-row';\nimport TextAlign from '@tiptap/extension-text-align';\nimport { NodeSelection } from '@tiptap/pm/state';\nimport StarterKit from '@tiptap/starter-kit';\nimport { EditorContent, useEditor } from '@tiptap/vue-3';\nimport { BubbleMenu } from '@tiptap/vue-3/menus';\nimport { type ComponentPublicInstance, computed, onBeforeUnmount, ref, watch } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\n\nimport { useClientRendered } from '../client-rendered';\nimport { VuetifyButtonSize } from '../input-base';\nimport { HtmlString, renderContentText } from '../render-content';\nimport { useTranslate } from '../translations';\n\nimport { ClassAttribute, Marker, Spoiler } from './block-styles';\nimport { createImagePasteHandler } from './image-paste';\nimport { LinkWithDownload } from './link-with-download';\nimport { MediaEmbed } from './media-embed';\nimport RtfToolbar from './rtf-toolbar.vue';\nimport { useEditorTick } from './use-editor-tick';\nimport { stripWordArtifacts } from './word-paste';\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string;\n minHeight?: string;\n disabled?: boolean;\n toolbarButtonSize?: VuetifyButtonSize;\n fontFamily?: string;\n }>(),\n { modelValue: '', minHeight: '7em', disabled: false, toolbarButtonSize: 'small', fontFamily: 'inherit' },\n);\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void;\n}>();\n\n// `<df-rtf-editor>`'s label is positioned by a fixed `translate()` in its own stylesheet, tuned around a\n// single-row toolbar - it has no other way to know the toolbar's actual height, since the label (drawn by\n// `v-field`'s `#label` slot) and the toolbar (drawn by this component, inside `v-field`'s default slot) are\n// siblings, not ancestor/descendant. Publishing the toolbar's measured height as a CSS custom property on their\n// shared `.v-field` ancestor lets that `translate()` read a real value instead of guessing one - it still needs\n// to reach up past this component's own root to a DOM node it doesn't otherwise touch, which is what the\n// `.closest()` below is for.\n// a function ref: a template ref by name would put the toolbar's types into the declarations this component emits\nconst toolbarRef = ref<ComponentPublicInstance | null>(null);\nfunction setToolbar(el: unknown) {\n toolbarRef.value = el as ComponentPublicInstance | null;\n}\nconst clientRendered = useClientRendered();\nconst valueText = computed(() => renderContentText(new HtmlString(props.modelValue ?? '')));\nconst t = useTranslate();\nlet toolbarResizeObserver: ResizeObserver | undefined;\n\n// the toolbar is rendered once the component renders in the browser, at mount or after it\nwatch(\n toolbarRef,\n (toolbar) => {\n toolbarResizeObserver?.disconnect();\n const toolbarEl = toolbar?.$el as HTMLElement | undefined;\n const fieldEl = toolbarEl?.closest<HTMLElement>('.v-field');\n if (!toolbarEl || !fieldEl) return;\n toolbarResizeObserver = new ResizeObserver(([entry]) => {\n fieldEl.style.setProperty('--rtf-toolbar-height', `${entry.contentRect.height}px`);\n });\n toolbarResizeObserver.observe(toolbarEl);\n },\n { flush: 'post' },\n);\nonBeforeUnmount(() => toolbarResizeObserver?.disconnect());\n\nconst editor = useEditor({\n content: props.modelValue,\n editable: !props.disabled,\n extensions: [\n StarterKit.configure({ link: false }),\n LinkWithDownload.configure({ openOnClick: false, autolink: true, defaultProtocol: 'https' }),\n Image.configure({\n inline: true,\n allowBase64: true,\n resize: {\n enabled: true,\n directions: ['top', 'right', 'bottom', 'left', 'top-left', 'top-right', 'bottom-left', 'bottom-right'],\n minWidth: 24,\n minHeight: 24,\n },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Table.configure({ resizable: true }),\n TableRow,\n TableHeader,\n TableCell,\n Placeholder.configure({ placeholder: '' }),\n ClassAttribute,\n Marker,\n Spoiler,\n MediaEmbed,\n ],\n editorProps: {\n attributes: { class: 'rtf-content' },\n transformPastedHTML: (html: string) => stripWordArtifacts(html),\n handlePaste: createImagePasteHandler(() => editor.value),\n },\n // ProseMirror's schema never lets the document itself be empty - a cleared editor still holds one empty\n // paragraph, whose serialized HTML is '<p></p>'. Emitting that instead of '' would make a `required` rule\n // checking for a falsy modelValue pass on a field the user never actually typed or pasted anything into.\n onUpdate: ({ editor: instance }) => {\n emit('update:modelValue', instance.isEmpty ? '' : instance.getHTML());\n },\n});\n\n// External writes (a reset, a different record loaded into the same form) are applied without re-emitting: the\n// third `setContent` argument suppresses the `update` this would otherwise trigger straight back out.\nwatch(\n () => props.modelValue,\n (value) => {\n const instance = editor.value;\n if (!instance) return;\n const incoming = value ?? '';\n if (incoming === instance.getHTML()) return;\n instance.commands.setContent(incoming, { emitUpdate: false });\n },\n);\n\n// setEditable emits an `update` unless told not to: it would write the editor's serialization of the value, which\n// differs from the value as written (`<b>` read back as `<strong>`), into the field the user has not edited\nwatch(\n () => props.disabled,\n (disabled) => editor.value?.setEditable(!disabled, false),\n);\nwatch(editor, (instance) => instance?.setEditable(!props.disabled, false));\n\nconst bubbleButtonProps = { icon: true, size: 'small', density: 'comfortable', variant: 'text' } as const;\n\nconst bubbleTick = useEditorTick(editor);\nconst bubbleState = computed(() => {\n void bubbleTick.value;\n return {\n bold: !!editor.value?.isActive('bold'),\n italic: !!editor.value?.isActive('italic'),\n link: !!editor.value?.isActive('link'),\n bulletList: !!editor.value?.isActive('bulletList'),\n orderedList: !!editor.value?.isActive('orderedList'),\n };\n});\n\n// A NodeSelection (an image, a table, a horizontal rule - anything selected as a whole rather than as text) is\n// excluded: bold/italic/link/list toggles don't apply to a selected node, so showing this text-formatting bubble\n// over one is just noise sitting on top of whatever selection UI that node has of its own (an image's resize\n// handles, for instance).\nfunction bubbleShouldShow({ state }: { state: { selection: { empty: boolean } } }) {\n return !state.selection.empty && !(state.selection instanceof NodeSelection);\n}\n\nfunction toggle(command: 'toggleBold' | 'toggleItalic' | 'toggleBulletList' | 'toggleOrderedList') {\n editor.value?.chain().focus()[command]().run();\n}\n\nfunction toggleBubbleLink() {\n const instance = editor.value;\n if (!instance) return;\n if (instance.isActive('link')) {\n instance.chain().focus().unsetLink().run();\n return;\n }\n\n const href = window.prompt(t('LinkUrl'));\n if (href) instance.chain().focus().extendMarkRange('link').setLink({ href }).run();\n}\n</script>\n\n<style>\n@media print {\n body {\n margin: 0 !important;\n }\n}\n\n.editor-container {\n font-family: v-bind(fontFamily);\n width: 100%;\n}\n\n.rtf-content {\n line-height: 1.6;\n word-break: break-word;\n min-height: v-bind(minHeight);\n padding: 0.5em 0.75em;\n background: rgb(var(--v-theme-surface));\n color: rgb(var(--v-theme-on-surface));\n outline: none;\n}\n\n.rtf-content p {\n margin: 0 0 1em;\n}\n\n/* ProseMirror's list/table schemas wrap every block of text in a <p>, list item or cell content included, so\n without this every list item and table cell would carry the same margin ordinary paragraphs do - list items\n readable as double-spaced lines, cells with dead space above and below their text. */\n.rtf-content li p,\n.rtf-content td p,\n.rtf-content th p {\n margin: 0;\n}\n\n.rtf-content li + li {\n margin-top: 0;\n}\n\n.rtf-content img {\n max-width: 100%;\n height: auto;\n}\n\n/* TipTap's image resize NodeView (@tiptap/extension-image's `resize` option) builds the handle elements below\n with no visual styling of their own - position only - so the consuming app is expected to supply the look. */\n.rtf-content [data-resize-handle] {\n background: rgb(var(--v-theme-primary));\n border: 1px solid rgb(var(--v-theme-surface));\n border-radius: 2px;\n opacity: 0;\n transition: opacity 0.1s ease;\n z-index: 1;\n}\n\n.rtf-content [data-resize-container]:hover [data-resize-handle],\n.rtf-content [data-resize-container]:focus-within [data-resize-handle] {\n opacity: 1;\n}\n\n.rtf-content [data-resize-handle='top'],\n.rtf-content [data-resize-handle='bottom'] {\n height: 6px;\n cursor: ns-resize;\n}\n\n.rtf-content [data-resize-handle='left'],\n.rtf-content [data-resize-handle='right'] {\n width: 6px;\n cursor: ew-resize;\n}\n\n.rtf-content [data-resize-handle='top-left'],\n.rtf-content [data-resize-handle='bottom-right'] {\n width: 10px;\n height: 10px;\n cursor: nwse-resize;\n}\n\n.rtf-content [data-resize-handle='top-right'],\n.rtf-content [data-resize-handle='bottom-left'] {\n width: 10px;\n height: 10px;\n cursor: nesw-resize;\n}\n\n/* Holding Shift while dragging a handle locks the aspect ratio (ResizableNodeView's own behaviour, not\n something this component adds) - a one-off tooltip on the corner handle most people reach for first is enough\n to surface it, rather than a whole toolbar for a modifier key. */\n.rtf-content [data-resize-handle='bottom-right']:hover::after {\n content: 'Hold Shift to keep the aspect ratio';\n position: absolute;\n bottom: 14px;\n right: 0;\n white-space: nowrap;\n font-size: 12px;\n padding: 2px 6px;\n border-radius: 4px;\n background: rgb(var(--v-theme-surface-variant));\n color: rgb(var(--v-theme-on-surface-variant));\n pointer-events: none;\n}\n\n.rtf-content iframe.media-embed {\n width: 100%;\n aspect-ratio: 16 / 9;\n margin: 1em 0;\n border: 0;\n}\n\n.rtf-bubble-menu {\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 2px;\n background: rgb(var(--v-theme-surface));\n border: 1px solid rgb(var(--v-theme-surface-variant));\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n}\n\n.rtf-content h3.category {\n font-size: 20px;\n font-weight: bold;\n color: #555;\n letter-spacing: 10px;\n margin: 0;\n padding: 0;\n}\n\n.rtf-content h2.document-title {\n font-size: 50px;\n font-weight: bold;\n margin: 0;\n padding: 0;\n border: 0;\n}\n\n.rtf-content h3.document-subtitle {\n font-size: 20px;\n color: #555;\n margin: 0 0 1em;\n font-weight: bold;\n padding: 0;\n}\n\n.rtf-content p.info-box {\n --background-size: 30px;\n --background-color: #e91e63;\n padding: 1.2em 2em;\n border: 1px solid var(--background-color);\n background:\n linear-gradient(\n 135deg,\n var(--background-color) 0%,\n var(--background-color) var(--background-size),\n transparent var(--background-size)\n ),\n linear-gradient(\n 135deg,\n transparent calc(100% - var(--background-size)),\n var(--background-color) calc(100% - var(--background-size)),\n var(--background-color)\n );\n border-radius: 10px;\n margin: 1.5em 2em;\n box-shadow: 5px 5px 0 #ffe6ef;\n}\n\n.rtf-content blockquote.side-quote {\n font-style: normal;\n float: right;\n width: 35%;\n position: relative;\n border: 0;\n overflow: visible;\n z-index: 1;\n margin-left: 1em;\n}\n\n.rtf-content blockquote.side-quote::before {\n content: '“';\n position: absolute;\n top: -37px;\n left: -10px;\n display: block;\n font-size: 200px;\n color: #e7e7e7;\n z-index: -1;\n line-height: 1;\n}\n\n.rtf-content blockquote.side-quote p {\n font-size: 2em;\n line-height: 1;\n}\n\n.rtf-content blockquote.side-quote p:last-child:not(:first-child) {\n font-size: 1.3em;\n text-align: right;\n color: #555;\n}\n\n.rtf-content span.marker {\n background: yellow;\n}\n\n.rtf-content span.spoiler {\n background: #000;\n color: #000;\n}\n\n.rtf-content span.spoiler:hover {\n background: #000;\n color: #fff;\n}\n\n.rtf-content pre.fancy-code {\n border: 0;\n margin-left: 2em;\n margin-right: 2em;\n border-radius: 10px;\n}\n\n.rtf-content pre.fancy-code::before {\n content: '';\n display: block;\n height: 13px;\n background: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NCAxMyI+CiAgPGNpcmNsZSBjeD0iNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGMzZCNUMiLz4KICA8Y2lyY2xlIGN4PSIyNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGOUJFNEQiLz4KICA8Y2lyY2xlIGN4PSI0Ny41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiM1NkM0NTMiLz4KPC9zdmc+Cg==);\n margin-bottom: 8px;\n background-repeat: no-repeat;\n}\n\n.rtf-content pre.fancy-code-dark {\n background: #272822;\n color: #fff;\n box-shadow: 5px 5px 0 #0000001f;\n}\n\n.rtf-content pre.fancy-code-bright {\n background: #dddfe0;\n color: #000;\n box-shadow: 5px 5px 0 #b3b3b3;\n}\n</style>\n","<template>\n <input-base v-bind=\"props\" class=\"rtf-editor\" :class=\"densityClass\">\n <template #default=\"slotProps\">\n <rtf-editor-core\n v-model=\"value\"\n :class=\"{ 'mt-6': !!label }\"\n :min-height=\"minHeight\"\n :disabled=\"vuetifyBindings.disabled\"\n :toolbar-button-size=\"toolbarButtonSize\"\n :font-family=\"fontFamily\"\n v-bind=\"passthroughAttrs\"\n @focusin=\"slotProps.focus()\"\n @focusout=\"slotProps.blur()\"\n />\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { DfRtfEditorProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, InputBase, useInputBase } from './helpers';\nimport RtfEditorCore from './helpers/rtf-editor/editor-core.vue';\n\nconst props = withDefaults(defineProps<DfRtfEditorProps>(), { ...defaultBaseProps, minHeight: undefined });\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, value, vuetifyBindings } = useInputBase(props, emits);\n</script>\n\n<style>\n.rtf-editor .v-field:not(.v-field--active) .v-label.v-field-label:not(.v-field-label--floating) {\n /* `--rtf-toolbar-height` is set by editor-core.vue's own `ResizeObserver`, straight onto this `.v-field`; the\n 3em fallback only matters before that first measurement lands or if it never does (a non-browser render).\n The added 0.5em is the gap between the toolbar's bottom edge and the label's own baseline - without it the\n label sits flush against the toolbar instead of inside the content area's padding. */\n transform: translate(0.5em, calc(var(--rtf-toolbar-height, 3em) + 1em));\n}\n\n.rtf-editor .v-input__control {\n /* So the toolbar's dropdown menus draw over vuetify inputs that are positioned underneath */\n z-index: 1;\n}\n</style>\n","<template>\n <input-base v-bind=\"props\" class=\"rtf-editor\" :class=\"densityClass\">\n <template #default=\"slotProps\">\n <rtf-editor-core\n v-model=\"value\"\n :class=\"{ 'mt-6': !!label }\"\n :min-height=\"minHeight\"\n :disabled=\"vuetifyBindings.disabled\"\n :toolbar-button-size=\"toolbarButtonSize\"\n :font-family=\"fontFamily\"\n v-bind=\"passthroughAttrs\"\n @focusin=\"slotProps.focus()\"\n @focusout=\"slotProps.blur()\"\n />\n </template>\n </input-base>\n</template>\n\n<script setup lang=\"ts\">\nimport { DfRtfEditorProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, InputBase, useInputBase } from './helpers';\nimport RtfEditorCore from './helpers/rtf-editor/editor-core.vue';\n\nconst props = withDefaults(defineProps<DfRtfEditorProps>(), { ...defaultBaseProps, minHeight: undefined });\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, value, vuetifyBindings } = useInputBase(props, emits);\n</script>\n\n<style>\n.rtf-editor .v-field:not(.v-field--active) .v-label.v-field-label:not(.v-field-label--floating) {\n /* `--rtf-toolbar-height` is set by editor-core.vue's own `ResizeObserver`, straight onto this `.v-field`; the\n 3em fallback only matters before that first measurement lands or if it never does (a non-browser render).\n The added 0.5em is the gap between the toolbar's bottom edge and the label's own baseline - without it the\n label sits flush against the toolbar instead of inside the content area's padding. */\n transform: translate(0.5em, calc(var(--rtf-toolbar-height, 3em) + 1em));\n}\n\n.rtf-editor .v-input__control {\n /* So the toolbar's dropdown menus draw over vuetify inputs that are positioned underneath */\n z-index: 1;\n}\n</style>\n","import { isArray, first, castArray } from 'lodash-es';\nimport { Ref } from 'vue';\n\nimport { SelectChoice } from './df-select.interface';\n\nexport function convertItems(items: SelectChoice[]) {\n return items.map((item) => ({ value: item.id, title: item.text, icon: item.icon }));\n}\n\n/**\n * multipleCompliantValue ensures that resulting value of the select component is\n * 1 - null, when nothing is selected\n * 2 - array, when multiple is truthy\n * 3 - ordinal / simple value when multiple is not truthy\n * @param value the value to make compliant\n * @param multiple indicator for multiple selection\n */\nexport function multipleCompliantValue(value: any, multiple: boolean): any {\n // Če je vrednost null ali undefined\n if (value == null) return null;\n\n // Če je prazno polje (za multiple)\n if (isArray(value) && value.length === 0) return null;\n\n // Za multiple vedno vrni polje\n if (multiple) return castArray(value);\n\n // Za single vrni prvo vrednost ali vrednost samo\n return isArray(value) ? (first(value) ?? null) : value;\n}\n\nexport function getSelectedChoices(loadedChoices: SelectChoice[], multipleCpliantValue: any | any[] | null) {\n if (multipleCpliantValue == null) return [];\n const mcValue = castArray(multipleCpliantValue);\n return loadedChoices.filter((choice) => mcValue.some((val: any) => val === choice.id));\n}\n\n/**\n * updateSelectedFromValue ensures that the actual select component receives model-value formatted to its needs\n */\nexport function updateSelectedFromValue(\n resultingValue: any,\n selected: Ref<any>,\n multiple: boolean,\n taggable: boolean,\n loadedChoices: SelectChoice[],\n) {\n const mcValue = multipleCompliantValue(resultingValue, multiple);\n\n if (mcValue == null) {\n selected.value = multiple ? [] : null;\n return;\n }\n\n if (multiple) {\n if (taggable) {\n // if taggable (can add new items not in choices), keep the value as-is\n selected.value = mcValue;\n } else {\n // when not taggable, we filter the result to existing choices\n selected.value = getSelectedChoices(loadedChoices, mcValue).map((choice) => choice.id);\n }\n } else {\n if (taggable) {\n // if taggable, we just keep the selected value\n selected.value = mcValue;\n } else {\n // when not taggable, we filter the result to existing choices\n const matchingChoice = first(getSelectedChoices(loadedChoices, mcValue));\n selected.value = matchingChoice?.id ?? null;\n }\n }\n}\n","<template>\n <v-text-field\n v-if=\"isRendered && !clientRendered\"\n :class=\"[cssClass, densityClass, visibilityClass]\"\n :model-value=\"chosenText\"\n v-bind=\"vuetifyBindings\"\n readonly\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n </v-text-field>\n <component\n :is=\"taggable ? 'v-combobox' : 'v-autocomplete'\"\n v-else-if=\"isRendered\"\n ref=\"dfSelectRef\"\n v-model=\"selected\"\n :class=\"[\n cssClass,\n densityClass,\n visibilityClass,\n { 'df-select-multirow': isMultiline, 'df-select-single': !multiple },\n ]\"\n :style=\"{ '--df-select-search-width': `${(searchText?.length ?? 0) + 1}ch` }\"\n :items=\"options\"\n :return-object=\"false\"\n chips\n :auto-select-first=\"true\"\n :closable-chips=\"allowNull || (multiple && selected.length > 1)\"\n :clearable=\"allowNull\"\n :multiple=\"multiple\"\n :loading=\"loading\"\n :hide-selected=\"false\"\n :aria-describedby=\"vuetifyBindings.helpText ? `${vuetifyBindings.name}-help` : null\"\n :menu-props=\"{ maxHeight: '400' }\"\n :search=\"searchText\"\n v-bind=\"vuetifyBindings\"\n @update:search=\"(query: any) => queryOptions(query, undefined)\"\n @update:model-value=\"onSelect\"\n @click:clear=\"selected = null\"\n @blur=\"touched = true\"\n @mousedown.capture=\"onMouseDown($event)\"\n >\n <template #chip=\"{ item }\">\n <v-chip\n :key=\"item.value\"\n label\n size=\"small\"\n class=\"d-flex align-middle\"\n :variant=\"multiple ? 'tonal' : 'text'\"\n :closable=\"multiple\"\n @click:close=\"chipClose($event, item.value)\"\n >\n <template #prepend>\n <cached-icon v-if=\"item.raw?.icon\" class=\"me-1\" :name=\"item.raw.icon\" />\n </template>\n <span :class=\"{ 'text-body-1': !multiple }\">{{ item.title }}</span>\n </v-chip>\n </template>\n <template #label=\"labelData\">\n <df-label :data=\"labelData\" :label=\"label\" />\n </template>\n\n <template #item=\"{ props: prps, item }\">\n <v-list-item v-bind=\"prps\">\n <template #prepend>\n <span v-if=\"item.raw?.icon\" class=\"me-1\">\n <cached-icon class=\"action-icon\" :name=\"item.raw.icon\" />\n </span>\n </template>\n </v-list-item>\n </template>\n <template #message=\"{ message }\">\n <df-input-hint :message=\"message\" :errors=\"shownErrors\" />\n </template>\n <template v-if=\"$slots['append-inner']\" #append-inner=\"props\">\n <slot name=\"append-inner\" v-bind=\"props\" />\n </template>\n <template v-if=\"$slots['prepend-inner']\" #prepend-inner=\"props\">\n <slot name=\"prepend-inner\" v-bind=\"props\" />\n </template>\n </component>\n</template>\n\n<script setup lang=\"ts\">\nimport { castArray, isEqual, unionBy } from 'lodash-es';\nimport { computed, nextTick, ref, toRefs, unref, watch } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\nimport { VAutocomplete, VCombobox } from 'vuetify/components';\n\nimport { DfSelectProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, SelectChoice, useInputBase } from './helpers';\nimport { useClientRendered } from './helpers/client-rendered';\nimport {\n convertItems,\n getSelectedChoices,\n multipleCompliantValue,\n updateSelectedFromValue,\n} from './helpers/df-select.helper';\n\nconst propsWithDefaults = withDefaults(defineProps<DfSelectProps>(), {\n ...defaultBaseProps,\n choices: undefined,\n multiple: false,\n allowTags: false,\n allowNull: true,\n fetchChoices: undefined,\n});\n\nconst { choices, multiple, allowTags: taggable, allowNull, cssClass } = toRefs(propsWithDefaults);\n\ninterface Emits extends BaseEmits {\n (e: 'update:modelValueDisplay', value: SelectChoice[]): any;\n}\n\nconst emits = defineEmits<Emits>();\ndefineSlots<{\n 'append-inner'?: (props: any) => any;\n 'prepend-inner'?: (props: any) => any;\n}>();\n\nconst dfSelectRef = ref<InstanceType<typeof VAutocomplete> | InstanceType<typeof VCombobox> | null>(null);\n\nconst {\n densityClass,\n isRendered,\n label,\n shownErrors,\n touched,\n value: resultingValue,\n visibilityClass,\n vuetifyBindings,\n} = useInputBase(propsWithDefaults, emits);\n\n// on the server and until it renders in the browser, the select is a text field holding the chosen choices' text:\n// Vuetify's autocomplete keeps its menu in memory after a server render\nconst clientRendered = useClientRendered();\nconst selected = ref<any>(null);\nconst takeLoaded = ref(false);\nconst loaded = ref<SelectChoice[]>([]);\nconst loadedChoices = computed<SelectChoice[]>(() => (unref(takeLoaded) ? unref(loaded) : unref(choices) || []));\n\nconst options = computed(() => convertItems(loadedChoices.value));\nconst chosenText = computed(() =>\n getSelectedChoices(loadedChoices.value, multipleCompliantValue(resultingValue.value, multiple.value))\n .map((choice) => choice.text)\n .join(', '),\n);\nconst searchText = ref<string | null>(null);\nconst fetchCounterGlobal = ref(0);\nconst isMultiline = ref(false);\n// Number of fetchChoices calls in flight that resolve ids held by the value (resolveValueChoices()). While any is\n// pending, loadedChoices is not yet complete for the value, so `selected` - which only holds ids loadedChoices has a\n// choice for - is not written back into the value: that would drop every id still being resolved.\nconst resolvingValue = ref(0);\n// Number of queryOptions() calls in flight.\nconst searching = ref(0);\nconst loading = computed(() => searching.value > 0 || resolvingValue.value > 0);\n\nif (choices.value?.length && propsWithDefaults.fetchChoices !== undefined) {\n console.warn('Both choices and fetchChoices are set. Only one of them should be set.');\n}\n\nfunction emitModelValueDisplay(mcVal: any) {\n emits('update:modelValueDisplay', getSelectedChoices(loadedChoices.value, mcVal));\n}\n\nconst setResultingValueGuard = ref(false);\n\nfunction setResultingValue(newValue: any) {\n setResultingValueGuard.value = true;\n try {\n resultingValue.value = newValue;\n } finally {\n // The guard suppresses the watch that pushes the model's value back into `selected`. A write the control does not\n // take verbatim - a ValueChangedAction that writes another value back, a handler that throws and unwinds it - never\n // reaches that watch, so the chips would go on showing a selection the control never took. Comparing what the\n // control holds against what was written is what restores it, and it needs a deep comparison: for multiple\n // selection the value reads back as a different array holding the same items. The comparison waits for the next\n // tick: under v-model the parent passes the written value back as modelValue only when it re-renders, and a read\n // before that sees the previous value, reverts the selection and emits it, which the parent passes back in turn -\n // the two keep swapping values without end.\n nextTick(() => {\n const current = multipleCompliantValue(resultingValue.value, multiple.value);\n if (!isEqual(current, newValue)) {\n updateSelectedFromValue(current, selected, multiple.value, taggable.value, loadedChoices.value);\n }\n setResultingValueGuard.value = false;\n });\n }\n}\n\nfunction getFullWidth(item: HTMLElement | null) {\n if (!item) return 0;\n const rect = item.getBoundingClientRect();\n const style = window.getComputedStyle(item);\n\n return rect.width + parseFloat(style.marginLeft) + parseFloat(style.marginRight);\n}\n\nfunction checkMultiline() {\n if (multiple.value && allowNull.value && selected.value != null && selected.value.length > 0 && dfSelectRef.value) {\n const dfSelect = dfSelectRef.value.$el;\n const inputWidth = dfSelect.querySelector('.v-input__control')?.clientWidth;\n const container = dfSelect.querySelector('.v-field__input');\n const items = container.querySelectorAll('.v-autocomplete__selection, .v-combobox__selection');\n\n const style = window.getComputedStyle(container);\n let selectedWidth = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);\n\n items.forEach((item: HTMLElement) => {\n selectedWidth += getFullWidth(item);\n });\n\n const clearableWidth = getFullWidth(dfSelect.querySelector('.v-field .v-field__clearable'));\n const appendWidth = getFullWidth(dfSelect.querySelector('.v-field .v-field__append-inner'));\n const chipGap = 2;\n isMultiline.value = inputWidth - selectedWidth - items.length * chipGap - appendWidth < clearableWidth;\n } else {\n isMultiline.value = false;\n }\n}\n\nfunction onMouseDown(event: MouseEvent) {\n // če je klik na close ikoni ali njenem childu\n const target = event.target;\n if (target instanceof HTMLElement && target.closest('.v-chip__close')) {\n event.stopPropagation();\n event.preventDefault();\n }\n}\n\nwatch(\n selected,\n (newValue) => {\n if (vuetifyBindings.value.readonly || resolvingValue.value > 0) return;\n nextTick(() => {\n const mcVal = multipleCompliantValue(newValue, multiple.value);\n emitModelValueDisplay(mcVal);\n setResultingValue(mcVal);\n });\n },\n { deep: true },\n);\nwatch(\n resultingValue,\n (newValue: any) => {\n if (setResultingValueGuard.value) return;\n const mcVal = multipleCompliantValue(newValue, multiple.value);\n const resolved = resolveValueChoices(mcVal);\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n resolved?.then(() => {\n // A value set while this call was in flight started its own resolution and owns `selected` from then on.\n if (!isEqual(multipleCompliantValue(resultingValue.value, multiple.value), mcVal)) return;\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n });\n },\n { deep: true },\n);\n\nwatch(setResultingValueGuard, () => {\n if (!setResultingValueGuard.value) {\n checkMultiline();\n }\n});\n\nfunction resetQuery() {\n if (searchText.value != null && searchText.value.length > 0) {\n searchText.value = null;\n queryOptions();\n }\n}\n\nfunction onSelect(/* val: any */) {\n resetQuery();\n if (vuetifyBindings.value.readonly || taggable.value) return;\n const mcVal = multipleCompliantValue(selected.value, multiple.value);\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n setResultingValue(mcVal);\n}\n\nfunction chipClose(event: MouseEvent, itemValue: any) {\n event.stopPropagation();\n if (vuetifyBindings.value.readonly || taggable.value) {\n if (taggable.value) {\n selected.value = selected.value.filter((v: any) => v !== itemValue);\n }\n return;\n }\n let mcVal;\n if (multiple.value && Array.isArray(selected.value)) {\n mcVal = multipleCompliantValue(\n selected.value.filter((v) => v !== itemValue),\n multiple.value,\n );\n } else {\n mcVal = null;\n }\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n setResultingValue(mcVal);\n}\n\nasync function queryOptions(queryValue?: any, idValue?: any): Promise<void> {\n if (vuetifyBindings.value.readonly) return;\n searchText.value = queryValue;\n if (choices.value || propsWithDefaults.fetchChoices === undefined) return;\n const fetchCounter = ++fetchCounterGlobal.value;\n searching.value++;\n try {\n const newChoices = await propsWithDefaults.fetchChoices(queryValue, idValue);\n if (fetchCounter !== fetchCounterGlobal.value) return;\n // Taken after the fetch, from the value: choices resolveValueChoices() loaded while this call was in flight\n // must survive the search results replacing the rest.\n const selectedChoices = getSelectedChoices(\n loadedChoices.value,\n multipleCompliantValue(resultingValue.value, multiple.value),\n );\n loaded.value = unionBy([...selectedChoices, ...newChoices], 'id');\n takeLoaded.value = true;\n } catch (error) {\n // a failed fetch leaves the choices as they are; a rejection out of here would be unhandled\n console.error(error);\n } finally {\n searching.value--;\n }\n}\n\n/**\n * Loads the choices for the ids in `mcVal` that loadedChoices has none for, through fetchChoices' idValue. Returns\n * null when there is nothing to load: no fetchChoices, a taggable select (its value is not limited to choices), or\n * every id already has its choice. An id fetchChoices returns no choice for stays without one, and the next\n * reconciliation against loadedChoices drops it from the value.\n */\nfunction resolveValueChoices(mcVal: any): Promise<void> | null {\n const fetchChoices = propsWithDefaults.fetchChoices;\n if (fetchChoices === undefined || taggable.value || mcVal == null) return null;\n const unresolved = castArray(mcVal).filter((val) => !loadedChoices.value.some((choice) => choice.id === val));\n if (!unresolved.length) return null;\n resolvingValue.value++;\n return (async () => {\n try {\n const newChoices = await fetchChoices(undefined, multiple.value ? unresolved : unresolved[0]);\n loaded.value = unionBy([...loadedChoices.value, ...newChoices], 'id');\n takeLoaded.value = true;\n } catch (error) {\n console.error(error);\n } finally {\n resolvingValue.value--;\n }\n })();\n}\n\nfunction initialValueCheck() {\n // A disabled select shows what the field holds and writes nothing into it: the field takes the write, and a\n // default chosen by the control would mark it changed and put the choice into the form's data.\n const readonly = vuetifyBindings.value.readonly;\n let val = resultingValue.value;\n if (!readonly && !allowNull.value && val == null && options.value.length) {\n // Starting settings: check if value is mandatory and select the first item from the options\n val = options.value[0].value;\n }\n val = multipleCompliantValue(val, multiple.value);\n updateSelectedFromValue(val, selected, multiple.value, taggable.value, loadedChoices.value);\n if (resolvingValue.value > 0) return;\n emitModelValueDisplay(val);\n if (!readonly) setResultingValue(val);\n}\n\n// Starting settings: with fetchChoices, a value is first resolved into its choices and only then reconciled against\n// them. Anything else - an empty value, a taggable select - goes through queryOptions() with the value as idValue.\n// On the server nothing is fetched, and a value is not reconciled against choices it has not loaded: the server\n// does not wait for a fetch, so its result would not reach the HTML.\nconst inBrowser = typeof window !== 'undefined';\nlet initialLoad: Promise<void> | null = null;\nif (propsWithDefaults.fetchChoices !== undefined && inBrowser) {\n initialLoad =\n resolveValueChoices(multipleCompliantValue(resultingValue.value, multiple.value)) ??\n queryOptions(undefined, resultingValue.value);\n}\n\nif (inBrowser || propsWithDefaults.fetchChoices === undefined) initialValueCheck();\n\ninitialLoad?.then(() => {\n initialValueCheck();\n});\n\n// a select enabled after mount states its default then\nwatch(\n () => vuetifyBindings.value.readonly,\n (readonly) => {\n if (!readonly) initialValueCheck();\n },\n);\n</script>\n\n<style scoped>\n/* Vuetify gives the search input a minimum width of 64px, which wraps it under a long chip of a single select before\n anything is typed. The input's minimum width is the text typed into it, up to the width of the\n field: it stays beside the chip while the text fits there, and wraps to a line of its own when it does not */\n.df-select-single :deep(.v-field__input > input) {\n min-width: min(var(--df-select-search-width), 100%);\n}\n\n.df-select-multirow :deep(.v-field__clearable) {\n position: absolute;\n}\n\n.df-select-multirow :deep(.v-field__append-inner) {\n margin-top: 24px;\n}\n\n.df-select-multirow :deep(.v-autocomplete .v-field:not(.v-field--focused) input) {\n min-width: 24px;\n}\n</style>\n","<template>\n <v-text-field\n v-if=\"isRendered && !clientRendered\"\n :class=\"[cssClass, densityClass, visibilityClass]\"\n :model-value=\"chosenText\"\n v-bind=\"vuetifyBindings\"\n readonly\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n </v-text-field>\n <component\n :is=\"taggable ? 'v-combobox' : 'v-autocomplete'\"\n v-else-if=\"isRendered\"\n ref=\"dfSelectRef\"\n v-model=\"selected\"\n :class=\"[\n cssClass,\n densityClass,\n visibilityClass,\n { 'df-select-multirow': isMultiline, 'df-select-single': !multiple },\n ]\"\n :style=\"{ '--df-select-search-width': `${(searchText?.length ?? 0) + 1}ch` }\"\n :items=\"options\"\n :return-object=\"false\"\n chips\n :auto-select-first=\"true\"\n :closable-chips=\"allowNull || (multiple && selected.length > 1)\"\n :clearable=\"allowNull\"\n :multiple=\"multiple\"\n :loading=\"loading\"\n :hide-selected=\"false\"\n :aria-describedby=\"vuetifyBindings.helpText ? `${vuetifyBindings.name}-help` : null\"\n :menu-props=\"{ maxHeight: '400' }\"\n :search=\"searchText\"\n v-bind=\"vuetifyBindings\"\n @update:search=\"(query: any) => queryOptions(query, undefined)\"\n @update:model-value=\"onSelect\"\n @click:clear=\"selected = null\"\n @blur=\"touched = true\"\n @mousedown.capture=\"onMouseDown($event)\"\n >\n <template #chip=\"{ item }\">\n <v-chip\n :key=\"item.value\"\n label\n size=\"small\"\n class=\"d-flex align-middle\"\n :variant=\"multiple ? 'tonal' : 'text'\"\n :closable=\"multiple\"\n @click:close=\"chipClose($event, item.value)\"\n >\n <template #prepend>\n <cached-icon v-if=\"item.raw?.icon\" class=\"me-1\" :name=\"item.raw.icon\" />\n </template>\n <span :class=\"{ 'text-body-1': !multiple }\">{{ item.title }}</span>\n </v-chip>\n </template>\n <template #label=\"labelData\">\n <df-label :data=\"labelData\" :label=\"label\" />\n </template>\n\n <template #item=\"{ props: prps, item }\">\n <v-list-item v-bind=\"prps\">\n <template #prepend>\n <span v-if=\"item.raw?.icon\" class=\"me-1\">\n <cached-icon class=\"action-icon\" :name=\"item.raw.icon\" />\n </span>\n </template>\n </v-list-item>\n </template>\n <template #message=\"{ message }\">\n <df-input-hint :message=\"message\" :errors=\"shownErrors\" />\n </template>\n <template v-if=\"$slots['append-inner']\" #append-inner=\"props\">\n <slot name=\"append-inner\" v-bind=\"props\" />\n </template>\n <template v-if=\"$slots['prepend-inner']\" #prepend-inner=\"props\">\n <slot name=\"prepend-inner\" v-bind=\"props\" />\n </template>\n </component>\n</template>\n\n<script setup lang=\"ts\">\nimport { castArray, isEqual, unionBy } from 'lodash-es';\nimport { computed, nextTick, ref, toRefs, unref, watch } from 'vue';\nimport { CachedIcon } from 'vue-cached-icon';\nimport { VAutocomplete, VCombobox } from 'vuetify/components';\n\nimport { DfSelectProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, SelectChoice, useInputBase } from './helpers';\nimport { useClientRendered } from './helpers/client-rendered';\nimport {\n convertItems,\n getSelectedChoices,\n multipleCompliantValue,\n updateSelectedFromValue,\n} from './helpers/df-select.helper';\n\nconst propsWithDefaults = withDefaults(defineProps<DfSelectProps>(), {\n ...defaultBaseProps,\n choices: undefined,\n multiple: false,\n allowTags: false,\n allowNull: true,\n fetchChoices: undefined,\n});\n\nconst { choices, multiple, allowTags: taggable, allowNull, cssClass } = toRefs(propsWithDefaults);\n\ninterface Emits extends BaseEmits {\n (e: 'update:modelValueDisplay', value: SelectChoice[]): any;\n}\n\nconst emits = defineEmits<Emits>();\ndefineSlots<{\n 'append-inner'?: (props: any) => any;\n 'prepend-inner'?: (props: any) => any;\n}>();\n\nconst dfSelectRef = ref<InstanceType<typeof VAutocomplete> | InstanceType<typeof VCombobox> | null>(null);\n\nconst {\n densityClass,\n isRendered,\n label,\n shownErrors,\n touched,\n value: resultingValue,\n visibilityClass,\n vuetifyBindings,\n} = useInputBase(propsWithDefaults, emits);\n\n// on the server and until it renders in the browser, the select is a text field holding the chosen choices' text:\n// Vuetify's autocomplete keeps its menu in memory after a server render\nconst clientRendered = useClientRendered();\nconst selected = ref<any>(null);\nconst takeLoaded = ref(false);\nconst loaded = ref<SelectChoice[]>([]);\nconst loadedChoices = computed<SelectChoice[]>(() => (unref(takeLoaded) ? unref(loaded) : unref(choices) || []));\n\nconst options = computed(() => convertItems(loadedChoices.value));\nconst chosenText = computed(() =>\n getSelectedChoices(loadedChoices.value, multipleCompliantValue(resultingValue.value, multiple.value))\n .map((choice) => choice.text)\n .join(', '),\n);\nconst searchText = ref<string | null>(null);\nconst fetchCounterGlobal = ref(0);\nconst isMultiline = ref(false);\n// Number of fetchChoices calls in flight that resolve ids held by the value (resolveValueChoices()). While any is\n// pending, loadedChoices is not yet complete for the value, so `selected` - which only holds ids loadedChoices has a\n// choice for - is not written back into the value: that would drop every id still being resolved.\nconst resolvingValue = ref(0);\n// Number of queryOptions() calls in flight.\nconst searching = ref(0);\nconst loading = computed(() => searching.value > 0 || resolvingValue.value > 0);\n\nif (choices.value?.length && propsWithDefaults.fetchChoices !== undefined) {\n console.warn('Both choices and fetchChoices are set. Only one of them should be set.');\n}\n\nfunction emitModelValueDisplay(mcVal: any) {\n emits('update:modelValueDisplay', getSelectedChoices(loadedChoices.value, mcVal));\n}\n\nconst setResultingValueGuard = ref(false);\n\nfunction setResultingValue(newValue: any) {\n setResultingValueGuard.value = true;\n try {\n resultingValue.value = newValue;\n } finally {\n // The guard suppresses the watch that pushes the model's value back into `selected`. A write the control does not\n // take verbatim - a ValueChangedAction that writes another value back, a handler that throws and unwinds it - never\n // reaches that watch, so the chips would go on showing a selection the control never took. Comparing what the\n // control holds against what was written is what restores it, and it needs a deep comparison: for multiple\n // selection the value reads back as a different array holding the same items. The comparison waits for the next\n // tick: under v-model the parent passes the written value back as modelValue only when it re-renders, and a read\n // before that sees the previous value, reverts the selection and emits it, which the parent passes back in turn -\n // the two keep swapping values without end.\n nextTick(() => {\n const current = multipleCompliantValue(resultingValue.value, multiple.value);\n if (!isEqual(current, newValue)) {\n updateSelectedFromValue(current, selected, multiple.value, taggable.value, loadedChoices.value);\n }\n setResultingValueGuard.value = false;\n });\n }\n}\n\nfunction getFullWidth(item: HTMLElement | null) {\n if (!item) return 0;\n const rect = item.getBoundingClientRect();\n const style = window.getComputedStyle(item);\n\n return rect.width + parseFloat(style.marginLeft) + parseFloat(style.marginRight);\n}\n\nfunction checkMultiline() {\n if (multiple.value && allowNull.value && selected.value != null && selected.value.length > 0 && dfSelectRef.value) {\n const dfSelect = dfSelectRef.value.$el;\n const inputWidth = dfSelect.querySelector('.v-input__control')?.clientWidth;\n const container = dfSelect.querySelector('.v-field__input');\n const items = container.querySelectorAll('.v-autocomplete__selection, .v-combobox__selection');\n\n const style = window.getComputedStyle(container);\n let selectedWidth = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);\n\n items.forEach((item: HTMLElement) => {\n selectedWidth += getFullWidth(item);\n });\n\n const clearableWidth = getFullWidth(dfSelect.querySelector('.v-field .v-field__clearable'));\n const appendWidth = getFullWidth(dfSelect.querySelector('.v-field .v-field__append-inner'));\n const chipGap = 2;\n isMultiline.value = inputWidth - selectedWidth - items.length * chipGap - appendWidth < clearableWidth;\n } else {\n isMultiline.value = false;\n }\n}\n\nfunction onMouseDown(event: MouseEvent) {\n // če je klik na close ikoni ali njenem childu\n const target = event.target;\n if (target instanceof HTMLElement && target.closest('.v-chip__close')) {\n event.stopPropagation();\n event.preventDefault();\n }\n}\n\nwatch(\n selected,\n (newValue) => {\n if (vuetifyBindings.value.readonly || resolvingValue.value > 0) return;\n nextTick(() => {\n const mcVal = multipleCompliantValue(newValue, multiple.value);\n emitModelValueDisplay(mcVal);\n setResultingValue(mcVal);\n });\n },\n { deep: true },\n);\nwatch(\n resultingValue,\n (newValue: any) => {\n if (setResultingValueGuard.value) return;\n const mcVal = multipleCompliantValue(newValue, multiple.value);\n const resolved = resolveValueChoices(mcVal);\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n resolved?.then(() => {\n // A value set while this call was in flight started its own resolution and owns `selected` from then on.\n if (!isEqual(multipleCompliantValue(resultingValue.value, multiple.value), mcVal)) return;\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n });\n },\n { deep: true },\n);\n\nwatch(setResultingValueGuard, () => {\n if (!setResultingValueGuard.value) {\n checkMultiline();\n }\n});\n\nfunction resetQuery() {\n if (searchText.value != null && searchText.value.length > 0) {\n searchText.value = null;\n queryOptions();\n }\n}\n\nfunction onSelect(/* val: any */) {\n resetQuery();\n if (vuetifyBindings.value.readonly || taggable.value) return;\n const mcVal = multipleCompliantValue(selected.value, multiple.value);\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n setResultingValue(mcVal);\n}\n\nfunction chipClose(event: MouseEvent, itemValue: any) {\n event.stopPropagation();\n if (vuetifyBindings.value.readonly || taggable.value) {\n if (taggable.value) {\n selected.value = selected.value.filter((v: any) => v !== itemValue);\n }\n return;\n }\n let mcVal;\n if (multiple.value && Array.isArray(selected.value)) {\n mcVal = multipleCompliantValue(\n selected.value.filter((v) => v !== itemValue),\n multiple.value,\n );\n } else {\n mcVal = null;\n }\n updateSelectedFromValue(mcVal, selected, multiple.value, false, loadedChoices.value);\n setResultingValue(mcVal);\n}\n\nasync function queryOptions(queryValue?: any, idValue?: any): Promise<void> {\n if (vuetifyBindings.value.readonly) return;\n searchText.value = queryValue;\n if (choices.value || propsWithDefaults.fetchChoices === undefined) return;\n const fetchCounter = ++fetchCounterGlobal.value;\n searching.value++;\n try {\n const newChoices = await propsWithDefaults.fetchChoices(queryValue, idValue);\n if (fetchCounter !== fetchCounterGlobal.value) return;\n // Taken after the fetch, from the value: choices resolveValueChoices() loaded while this call was in flight\n // must survive the search results replacing the rest.\n const selectedChoices = getSelectedChoices(\n loadedChoices.value,\n multipleCompliantValue(resultingValue.value, multiple.value),\n );\n loaded.value = unionBy([...selectedChoices, ...newChoices], 'id');\n takeLoaded.value = true;\n } catch (error) {\n // a failed fetch leaves the choices as they are; a rejection out of here would be unhandled\n console.error(error);\n } finally {\n searching.value--;\n }\n}\n\n/**\n * Loads the choices for the ids in `mcVal` that loadedChoices has none for, through fetchChoices' idValue. Returns\n * null when there is nothing to load: no fetchChoices, a taggable select (its value is not limited to choices), or\n * every id already has its choice. An id fetchChoices returns no choice for stays without one, and the next\n * reconciliation against loadedChoices drops it from the value.\n */\nfunction resolveValueChoices(mcVal: any): Promise<void> | null {\n const fetchChoices = propsWithDefaults.fetchChoices;\n if (fetchChoices === undefined || taggable.value || mcVal == null) return null;\n const unresolved = castArray(mcVal).filter((val) => !loadedChoices.value.some((choice) => choice.id === val));\n if (!unresolved.length) return null;\n resolvingValue.value++;\n return (async () => {\n try {\n const newChoices = await fetchChoices(undefined, multiple.value ? unresolved : unresolved[0]);\n loaded.value = unionBy([...loadedChoices.value, ...newChoices], 'id');\n takeLoaded.value = true;\n } catch (error) {\n console.error(error);\n } finally {\n resolvingValue.value--;\n }\n })();\n}\n\nfunction initialValueCheck() {\n // A disabled select shows what the field holds and writes nothing into it: the field takes the write, and a\n // default chosen by the control would mark it changed and put the choice into the form's data.\n const readonly = vuetifyBindings.value.readonly;\n let val = resultingValue.value;\n if (!readonly && !allowNull.value && val == null && options.value.length) {\n // Starting settings: check if value is mandatory and select the first item from the options\n val = options.value[0].value;\n }\n val = multipleCompliantValue(val, multiple.value);\n updateSelectedFromValue(val, selected, multiple.value, taggable.value, loadedChoices.value);\n if (resolvingValue.value > 0) return;\n emitModelValueDisplay(val);\n if (!readonly) setResultingValue(val);\n}\n\n// Starting settings: with fetchChoices, a value is first resolved into its choices and only then reconciled against\n// them. Anything else - an empty value, a taggable select - goes through queryOptions() with the value as idValue.\n// On the server nothing is fetched, and a value is not reconciled against choices it has not loaded: the server\n// does not wait for a fetch, so its result would not reach the HTML.\nconst inBrowser = typeof window !== 'undefined';\nlet initialLoad: Promise<void> | null = null;\nif (propsWithDefaults.fetchChoices !== undefined && inBrowser) {\n initialLoad =\n resolveValueChoices(multipleCompliantValue(resultingValue.value, multiple.value)) ??\n queryOptions(undefined, resultingValue.value);\n}\n\nif (inBrowser || propsWithDefaults.fetchChoices === undefined) initialValueCheck();\n\ninitialLoad?.then(() => {\n initialValueCheck();\n});\n\n// a select enabled after mount states its default then\nwatch(\n () => vuetifyBindings.value.readonly,\n (readonly) => {\n if (!readonly) initialValueCheck();\n },\n);\n</script>\n\n<style scoped>\n/* Vuetify gives the search input a minimum width of 64px, which wraps it under a long chip of a single select before\n anything is typed. The input's minimum width is the text typed into it, up to the width of the\n field: it stays beside the chip while the text fits there, and wraps to a line of its own when it does not */\n.df-select-single :deep(.v-field__input > input) {\n min-width: min(var(--df-select-search-width), 100%);\n}\n\n.df-select-multirow :deep(.v-field__clearable) {\n position: absolute;\n}\n\n.df-select-multirow :deep(.v-field__append-inner) {\n margin-top: 24px;\n}\n\n.df-select-multirow :deep(.v-autocomplete .v-field:not(.v-field--focused) input) {\n min-width: 24px;\n}\n</style>\n","<template>\n <div v-if=\"isRendered\" class=\"df-textarea-container\" :class=\"[densityClass, visibilityClass]\">\n <v-textarea\n v-model=\"value\"\n :class=\"cssClass\"\n :rows=\"rows\"\n :auto-grow=\"(maxRows || 0) > 0\"\n :max-rows=\"maxRows\"\n v-bind=\"vuetifyBindings as any\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n </v-textarea>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { toRefs } from 'vue';\n\nimport { DfTextAreaProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfTextAreaProps>(), {\n ...defaultBaseProps,\n rows: undefined,\n maxRows: undefined,\n});\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, shownErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\nconst { cssClass } = toRefs(props);\n</script>\n","<template>\n <div v-if=\"isRendered\" class=\"df-textarea-container\" :class=\"[densityClass, visibilityClass]\">\n <v-textarea\n v-model=\"value\"\n :class=\"cssClass\"\n :rows=\"rows\"\n :auto-grow=\"(maxRows || 0) > 0\"\n :max-rows=\"maxRows\"\n v-bind=\"vuetifyBindings as any\"\n @blur=\"touched = true\"\n >\n <template #label=\"labelData\"><df-label :data=\"labelData\" :label=\"label\" /></template>\n <template #message=\"{ message }\"><df-input-hint :message=\"message\" :errors=\"shownErrors\" /></template>\n </v-textarea>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { toRefs } from 'vue';\n\nimport { DfTextAreaProps } from './dynamicforms-component-props';\nimport { BaseEmits, defaultBaseProps, DfInputHint, DfLabel, useInputBase } from './helpers';\n\nconst props = withDefaults(defineProps<DfTextAreaProps>(), {\n ...defaultBaseProps,\n rows: undefined,\n maxRows: undefined,\n});\n\ninterface Emits extends BaseEmits {}\nconst emits = defineEmits<Emits>();\n\nconst { densityClass, isRendered, label, shownErrors, touched, value, visibilityClass, vuetifyBindings } = useInputBase(\n props,\n emits,\n);\nconst { cssClass } = toRefs(props);\n</script>\n","export { default as DfActions } from './df-actions.vue';\nexport { default as DfCheckbox } from './df-checkbox.vue';\nexport { default as DfColor } from './df-color.vue';\nexport { default as DfDateTime } from './df-datetime.vue';\nexport { default as DfFile } from './df-file.vue';\nexport { default as DfImage } from './df-image.vue';\nexport { default as DfInput } from './df-input.vue';\nexport { default as DfInputHint } from './helpers/df-input-hint.vue';\nexport { default as DfLabel } from './helpers/df-label.vue';\nexport { default as DfRtfEditor } from './df-rtf-editor.vue';\nexport { default as DfSelect } from './df-select.vue';\nexport { default as DfTextArea } from './df-text-area.vue';\n","export { VAutocomplete } from 'vuetify/components/VAutocomplete';\nexport { VBtn } from 'vuetify/components/VBtn';\nexport { VBtnGroup } from 'vuetify/components/VBtnGroup';\nexport { VBtnToggle } from 'vuetify/components/VBtnToggle';\nexport { VCard, VCardActions } from 'vuetify/components/VCard';\nexport { VCheckbox } from 'vuetify/components/VCheckbox';\nexport { VChip } from 'vuetify/components/VChip';\nexport { VCombobox } from 'vuetify/components/VCombobox';\nexport { VColorPicker } from 'vuetify/components/VColorPicker';\nexport { VConfirmEdit } from 'vuetify/components/VConfirmEdit';\nexport { VDatePicker } from 'vuetify/components/VDatePicker';\nexport { VDivider } from 'vuetify/components/VDivider';\nexport { VField } from 'vuetify/components/VField';\nexport { VFileInput } from 'vuetify/components/VFileInput';\nexport { VRow, VCol } from 'vuetify/components/VGrid';\nexport { VIcon } from 'vuetify/components/VIcon';\nexport { VImg } from 'vuetify/components/VImg';\nexport { VInput } from 'vuetify/components/VInput';\nexport { VList, VListItem, VListItemTitle } from 'vuetify/components/VList';\nexport { VMenu } from 'vuetify/components/VMenu';\nexport { VNumberInput } from 'vuetify/components/VNumberInput';\nexport { VProgressLinear } from 'vuetify/components/VProgressLinear';\nexport { VSelect } from 'vuetify/components/VSelect';\nexport { VSwitch } from 'vuetify/components/VSwitch';\nexport { VTextarea } from 'vuetify/components/VTextarea';\nexport { VTextField } from 'vuetify/components/VTextField';\nexport { VTimePicker } from 'vuetify/components/VTimePicker';\n\n// run this in the src folder to get list of used components\n// grep -r -o \"<v-[a-zA-Z0-9-]*\" --include=\"*.vue\" . | sed 's/.*:<//' | sort | uniq\n","import {\n DfActions,\n DfCheckbox,\n DfColor,\n DfDateTime,\n DfFile,\n DfImage,\n DfInput,\n DfInputHint,\n DfLabel,\n DfRtfEditor,\n DfSelect,\n DfTextArea,\n} from './dynamicforms-components';\n\n/**\n * Every component this library draws with, keyed by the tag a layout names it by.\n *\n * A rendering layer that resolves a component by name out of a map - `@dynamicforms/vuetify-modal-form-kit`'s\n * `<component-render>` is one - takes it from here, so a component this package adds is in the map.\n *\n * The keys are the kebab-case of the export names, so a tag names the same component whether it is looked up\n * here or left to Vue's own resolver after `DynamicFormsInputs` has registered the components globally.\n */\nexport const dfInputComponentsByTag = {\n 'df-actions': DfActions,\n 'df-checkbox': DfCheckbox,\n 'df-color': DfColor,\n 'df-date-time': DfDateTime,\n 'df-file': DfFile,\n 'df-image': DfImage,\n 'df-input': DfInput,\n 'df-input-hint': DfInputHint,\n 'df-label': DfLabel,\n 'df-rtf-editor': DfRtfEditor,\n 'df-select': DfSelect,\n 'df-text-area': DfTextArea,\n} as const;\n\n/** The tags {@link dfInputComponentsByTag} answers for. */\nexport type DfInputComponentTag = keyof typeof dfInputComponentsByTag;\n","import { Action } from '@dynamicforms/vue-forms';\nimport { type Locale } from 'date-fns';\nimport { MaybeRef } from 'vue';\n\nimport {\n BaseProps,\n type ClassTypes,\n type ErrorInput,\n FileComms,\n Label,\n type RenderableValue,\n type RenderContentRef,\n SelectChoice,\n SelectFetchChoices,\n VuetifyButtonSize,\n VuetifyDensity,\n} from './helpers';\n\ntype ShowAsGroup = 'no' | 'grouped' | 'grouped-no-borders';\n\nexport interface DfActionsProps {\n /** The actions to draw, this library's `Action` or a bare `@dynamicforms/vue-forms` one: what each button\n * renders as is read off the action's value, and a value stating nothing renders as the defaults. */\n actions: MaybeRef<Action[]>;\n buttonSize?: VuetifyButtonSize; // see https://vuetifyjs.com/en/api/v-btn/#props-size\n /** Forwarded to each button's `density` prop. See https://vuetifyjs.com/en/api/v-btn/#props-density */\n buttonDensity?: VuetifyDensity;\n showAsGroup?: ShowAsGroup;\n}\n\nexport interface DfCheckboxProps extends BaseProps {\n allowNull?: boolean;\n}\n\nexport interface DfColorProps extends BaseProps {\n allowNull?: boolean;\n}\n\nexport interface DfDateTimeProps extends BaseProps {\n inputType?: 'datetime' | 'date' | 'time';\n displayFormatDate?: string;\n displayFormatTime?: string;\n locale?: Locale;\n}\n\nexport interface DfFileProps extends BaseProps {\n comms: FileComms;\n /** Milliseconds between keep-alive touches. Overrides `defaultTouchInterval` from the plugin's\n * `VuetifyInputsSettings`, which in turn overrides the baked-in default of 60000. */\n touchInterval?: number;\n}\n\n/**\n * `comms.upload` must resolve to a value directly usable as an `<img>` src (typically the URL your backend\n * serves the image from): the component has no separate lookup for turning an identifier into a display URL,\n * so it renders `modelValue` itself as the preview once a file has been uploaded.\n */\nexport interface DfImageProps extends BaseProps {\n comms: FileComms;\n /** Milliseconds between keep-alive touches. Overrides `defaultTouchInterval` from the plugin's\n * `VuetifyInputsSettings`, which in turn overrides the baked-in default of 60000. */\n touchInterval?: number;\n}\n\nexport interface DfInputProps extends BaseProps {\n inputType?: 'text' | 'password' | 'email' | 'url' | 'number';\n precision?: number | null;\n step?: number;\n min?: number;\n max?: number;\n}\n\nexport interface MessagesWidgetProps {\n /** A plain text, or the items to render, each in its own element: a `RenderableValue` as its content, an error\n * as `errorText()` gives it. */\n message: string | readonly (RenderableValue | ErrorInput)[];\n /** Classes for every rendered item, beside the item's own `extraClasses`. */\n classes?: ClassTypes;\n}\n\nexport interface DfInputHintProps {\n /** The errors to render, in place of {@link message} whenever there is one. A string is text in the user's\n * language; an error description may lack any member. */\n errors?: string | readonly (RenderableValue | ErrorInput)[];\n /** The message to render, shown while there is no error: content in any of its forms, or the items to render. */\n message?: RenderContentRef | readonly RenderableValue[];\n /** Classes for the rendered errors. Defaults to `text-error`. */\n errorClasses?: ClassTypes;\n /** Classes for the rendered message. Defaults to no class. */\n messageClasses?: ClassTypes;\n}\n\nexport interface DfLabelProps {\n /** The slot data Vuetify hands a `#label` slot. Its `label`, the label's text, is rendered where {@link label} has\n * no content. */\n data?: { label?: string; props?: Record<string, unknown> };\n /** The label to render: its content in any of the four forms, and the icon it carries. */\n label: Label;\n /** Whether the label wraps over several lines. It is rendered on one line by default. */\n allowWrap?: boolean;\n}\n\nexport interface DfRtfEditorProps extends BaseProps {\n minHeight?: string;\n /** Size of the toolbar's buttons, forwarded to each one's `size` prop (`v-btn`'s, or `<df-actions>`'s\n * `buttonSize` for the grouped clusters). See https://vuetifyjs.com/en/api/v-btn/#props-size */\n toolbarButtonSize?: VuetifyButtonSize;\n /** `font-family` of the editing area and its named block styles (Title, Subtitle, Info box, Side quote, article\n * category). Defaults to `'inherit'`: the component loads no font of its own, so the editor renders in whatever\n * font the surrounding page already set. Pass any valid CSS `font-family` value to override it; loading the\n * font itself, if it isn't a system font, is the application's responsibility. */\n fontFamily?: string;\n}\n\nexport interface DfSelectProps extends BaseProps {\n choices?: SelectChoice[];\n multiple?: boolean;\n allowTags?: boolean;\n allowNull?: boolean;\n fetchChoices?: SelectFetchChoices;\n}\n\nexport interface DfTextAreaProps extends BaseProps {\n rows?: number;\n maxRows?: number;\n}\n","import { App } from 'vue';\n\nimport * as Inputs from './dynamicforms-components';\nimport { VuetifyInputsSettings, vuetifyInputsSettingsKey } from './helpers';\nimport * as VuetifyComponents from './vuetify-components';\n\nexport * from './helpers';\nexport * as VuetifyComponents from './vuetify-components';\nexport * from './dynamicforms-components';\nexport * from './dynamicforms-components-by-tag';\nexport * as DfInputComponents from './dynamicforms-components';\nexport * as DfInputComponentProps from './dynamicforms-component-props';\n\nexport interface DynamicFormsInputsOptions extends VuetifyInputsSettings {\n registerComponents: boolean;\n registerVuetifyComponents: boolean;\n}\n\nexport const DynamicFormsInputs = {\n install: (app: App, options?: Partial<DynamicFormsInputsOptions>) => {\n app.provide(vuetifyInputsSettingsKey, options ?? {});\n if (options?.registerComponents ?? false) {\n Object.entries(Inputs).map(([name, component]) => app.component(name, component));\n }\n if (options?.registerVuetifyComponents ?? false) {\n Object.entries(VuetifyComponents).map(([name, component]) => app.component(name, component));\n }\n },\n};\n"],"x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,GAAa,GAAK;CACzB,OAAO,EAAI,QAAQ,KAAA;AACrB;AAEA,IAAM,KAAuB;CAC3B,kBAAkB;EAChB,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,QAAQ;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;CACF;CAEA,UAAU;EACR,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,QAAQ;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;CACF;CAEA,aAAa;CAEb,kBAAkB;EAChB,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,QAAQ;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;CACF;CAEA,UAAU;EACR,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,QAAQ;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;CACF;CAEA,aAAa;EACX,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,QAAQ;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;CACF;CAEA,QAAQ;EACN,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,QAAQ;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;CACF;CAEA,OAAO;EACL,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,QAAQ;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;CACF;CAGA,aAAa;EACX,KAAK;EACL,KAAK;EACL,KAAK;EACL,OAAO;CACT;CAGA,QAAQ;EACN,KAAK;EACL,KAAK;EACL,KAAK;EACL,OAAO;CACT;CAEA,cAAc;EACZ,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,QAAQ;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;CACF;CAEA,SAAS;EACP,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,QAAQ;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;CACF;CAEA,aAAa;EACX,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,QAAQ;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;CACF;CAEA,QAAQ;EACN,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,QAAQ;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;CACF;CAEA,YAAY;EACV,SAAS;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;EACT;EACA,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK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"}
|