fds-vue-core 7.1.6 → 7.1.8
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/components.d.ts +2 -2
- package/dist/components/Form/FdsTextarea/FdsTextarea.stories.d.ts +1 -0
- package/dist/components/Form/FdsTextarea/FdsTextarea.vue.d.ts +4 -2
- package/dist/components/Form/FdsTextarea/types.d.ts +10 -0
- package/dist/fds-vue-core.cjs.js +70 -24
- package/dist/fds-vue-core.cjs.js.map +1 -1
- package/dist/fds-vue-core.css +1 -1
- package/dist/fds-vue-core.es.js +70 -24
- package/dist/fds-vue-core.es.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/components/Form/FdsInput/FdsInput.vue +2 -2
- package/src/components/Form/FdsSelect/FdsSelect.vue +2 -2
- package/src/components/Form/FdsTextarea/FdsTextarea.stories.ts +16 -0
- package/src/components/Form/FdsTextarea/FdsTextarea.vue +62 -22
- package/src/components/Form/FdsTextarea/types.ts +11 -0
- package/src/index.ts +1 -1
- package/src/lang/en.json +1 -0
- package/src/lang/sv.json +1 -0
- package/src/plugin/useFdsI18n.ts +21 -5
package/components.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ import type { FdsCheckboxProps } from './src/components/Form/FdsCheckbox/types'
|
|
|
31
31
|
import type { FdsInputProps } from './src/components/Form/FdsInput/types'
|
|
32
32
|
import type { FdsRadioProps } from './src/components/Form/FdsRadio/types'
|
|
33
33
|
import type { FdsSelectProps } from './src/components/Form/FdsSelect/types'
|
|
34
|
-
import type { FdsTextareaProps } from './src/components/Form/FdsTextarea/types'
|
|
34
|
+
import type { FdsTextareaEmits, FdsTextareaProps } from './src/components/Form/FdsTextarea/types'
|
|
35
35
|
import type { FdsTableProps } from './src/components/Table/FdsTable/types'
|
|
36
36
|
import type { FdsTableHeadProps } from './src/components/Table/FdsTableHead/types'
|
|
37
37
|
import type { FdsTabsProps } from './src/components/Tabs/FdsTabs/types'
|
|
@@ -61,7 +61,7 @@ declare module 'vue' {
|
|
|
61
61
|
FdsRadio: DefineComponent<FdsRadioProps>
|
|
62
62
|
FdsInput: DefineComponent<FdsInputProps>
|
|
63
63
|
FdsCheckbox: DefineComponent<FdsCheckboxProps>
|
|
64
|
-
FdsTextarea: DefineComponent<FdsTextareaProps>
|
|
64
|
+
FdsTextarea: DefineComponent<FdsTextareaProps, {}, {}, {}, {}, {}, {}, FdsTextareaEmits>
|
|
65
65
|
FdsSelect: DefineComponent<FdsSelectProps>
|
|
66
66
|
FdsTable: DefineComponent<FdsTableProps>
|
|
67
67
|
FdsTableHead: DefineComponent<FdsTableHeadProps>
|
|
@@ -4,19 +4,21 @@ type __VLS_PublicProps = {
|
|
|
4
4
|
modelValue?: string;
|
|
5
5
|
} & __VLS_Props;
|
|
6
6
|
declare const _default: import('vue').DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
7
|
-
"update:modelValue": (value: string) => any;
|
|
8
|
-
} & {
|
|
9
7
|
input: (ev: Event) => any;
|
|
10
8
|
blur: (ev: FocusEvent) => any;
|
|
11
9
|
change: (ev: Event) => any;
|
|
10
|
+
valid: (value: boolean | null) => any;
|
|
12
11
|
"update:value": (value: string) => any;
|
|
12
|
+
"update:modelValue": (value: string) => any;
|
|
13
13
|
}, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
14
14
|
onInput?: ((ev: Event) => any) | undefined;
|
|
15
15
|
onBlur?: ((ev: FocusEvent) => any) | undefined;
|
|
16
16
|
onChange?: ((ev: Event) => any) | undefined;
|
|
17
|
+
onValid?: ((value: boolean | null) => any) | undefined;
|
|
17
18
|
"onUpdate:value"?: ((value: string) => any) | undefined;
|
|
18
19
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
19
20
|
}>, {
|
|
21
|
+
maxlength: number;
|
|
20
22
|
value: string;
|
|
21
23
|
dataTestid: string;
|
|
22
24
|
label: string;
|
|
@@ -11,5 +11,15 @@ export interface FdsTextareaProps extends Omit</* @vue-ignore */ TextareaHTMLAtt
|
|
|
11
11
|
};
|
|
12
12
|
dataTestid?: string;
|
|
13
13
|
inputClass?: string | Record<string, boolean> | Array<string | Record<string, boolean>>;
|
|
14
|
+
/** Character limit for counter/validation. Does not set native maxlength on the textarea. */
|
|
15
|
+
maxlength?: number;
|
|
14
16
|
value?: string;
|
|
15
17
|
}
|
|
18
|
+
export interface FdsTextareaEmits {
|
|
19
|
+
input: [ev: Event];
|
|
20
|
+
change: [ev: Event];
|
|
21
|
+
'update:value': [value: string];
|
|
22
|
+
blur: [ev: FocusEvent];
|
|
23
|
+
/** Emitted when maxlength is set: true/false for within/over limit, null when maxlength is unset. */
|
|
24
|
+
valid: [value: boolean | null];
|
|
25
|
+
}
|
package/dist/fds-vue-core.cjs.js
CHANGED
|
@@ -83,6 +83,7 @@ const en = {
|
|
|
83
83
|
"FdsSearchSelectPro.loadingMore": "Loading more...",
|
|
84
84
|
"FdsSearchSelectPro.showMore": "Show more",
|
|
85
85
|
"FdsSearchSelectPro.unspecified": "Unspecified",
|
|
86
|
+
"FdsTextarea.characters": "characters",
|
|
86
87
|
"FdsTreeView.childrenCountPrefix": "(+",
|
|
87
88
|
"FdsTreeView.closePopover": "Close",
|
|
88
89
|
"FdsTreeView.collapseNode": "Collapse {title}",
|
|
@@ -144,6 +145,7 @@ const sv = {
|
|
|
144
145
|
"FdsSearchSelectPro.loadingMore": "Hämtar fler...",
|
|
145
146
|
"FdsSearchSelectPro.showMore": "Visa fler",
|
|
146
147
|
"FdsSearchSelectPro.unspecified": "Ospecificerat",
|
|
148
|
+
"FdsTextarea.characters": "tecken",
|
|
147
149
|
"FdsTreeView.childrenCountPrefix": "(+",
|
|
148
150
|
"FdsTreeView.closePopover": "Stäng",
|
|
149
151
|
"FdsTreeView.collapseNode": "Fäll ihop {title}",
|
|
@@ -187,15 +189,26 @@ const useFdsI18n = () => {
|
|
|
187
189
|
if (!values) return message2;
|
|
188
190
|
return Object.entries(values).reduce((acc, [name, value]) => acc.split(`{${name}}`).join(String(value)), message2);
|
|
189
191
|
};
|
|
192
|
+
const silentTranslateOptions = { missingWarn: false, fallbackWarn: false };
|
|
193
|
+
const translateFromDictionary = (key, values) => {
|
|
194
|
+
const value = dictionary.value[key];
|
|
195
|
+
if (typeof value !== "string") return void 0;
|
|
196
|
+
return interpolate(value, values);
|
|
197
|
+
};
|
|
190
198
|
const t = (key, values) => {
|
|
191
199
|
const translateFn = i18n?.global?.t ?? i18n?.t;
|
|
192
200
|
if (typeof translateFn === "function") {
|
|
193
|
-
|
|
194
|
-
if (
|
|
201
|
+
let translated;
|
|
202
|
+
if (values != null && Object.keys(values).length > 0) {
|
|
203
|
+
translated = translateFn(key, values, silentTranslateOptions);
|
|
204
|
+
} else {
|
|
205
|
+
translated = translateFn(key, "", silentTranslateOptions);
|
|
206
|
+
}
|
|
207
|
+
if (typeof translated === "string" && translated !== key && translated !== "") {
|
|
208
|
+
return translated;
|
|
209
|
+
}
|
|
195
210
|
}
|
|
196
|
-
|
|
197
|
-
if (typeof value !== "string") return "";
|
|
198
|
-
return interpolate(value, values);
|
|
211
|
+
return translateFromDictionary(key, values) ?? key;
|
|
199
212
|
};
|
|
200
213
|
return {
|
|
201
214
|
i18n,
|
|
@@ -8889,7 +8902,7 @@ const _hoisted_2$f = { class: "relative" };
|
|
|
8889
8902
|
const _hoisted_3$c = ["type", "required", "value", "disabled", "tabindex", "aria-invalid", "aria-label", "aria-labelledby", "aria-describedby", "autocomplete", "pattern", "searchIcon"];
|
|
8890
8903
|
const _hoisted_4$b = {
|
|
8891
8904
|
key: 0,
|
|
8892
|
-
class: "text-red-
|
|
8905
|
+
class: "text-red-700 font-bold mt-1"
|
|
8893
8906
|
};
|
|
8894
8907
|
const _sfc_main$s = /* @__PURE__ */ vue.defineComponent({
|
|
8895
8908
|
...{
|
|
@@ -9226,7 +9239,7 @@ const _sfc_main$s = /* @__PURE__ */ vue.defineComponent({
|
|
|
9226
9239
|
isInvalid.value ? (vue.openBlock(), vue.createBlock(_sfc_main$J, {
|
|
9227
9240
|
key: 1,
|
|
9228
9241
|
name: "alert",
|
|
9229
|
-
class: "fill-red-
|
|
9242
|
+
class: "fill-red-700"
|
|
9230
9243
|
})) : vue.createCommentVNode("", true),
|
|
9231
9244
|
isValid2.value ? (vue.openBlock(), vue.createBlock(_sfc_main$J, {
|
|
9232
9245
|
key: 2,
|
|
@@ -16073,7 +16086,7 @@ const _hoisted_5$2 = ["value", "disabled"];
|
|
|
16073
16086
|
const _hoisted_6 = { class: "absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none" };
|
|
16074
16087
|
const _hoisted_7 = {
|
|
16075
16088
|
key: 2,
|
|
16076
|
-
class: "text-red-
|
|
16089
|
+
class: "text-red-700 font-bold mt-1"
|
|
16077
16090
|
};
|
|
16078
16091
|
const _sfc_main$9 = /* @__PURE__ */ vue.defineComponent({
|
|
16079
16092
|
...{
|
|
@@ -16140,7 +16153,7 @@ const _sfc_main$9 = /* @__PURE__ */ vue.defineComponent({
|
|
|
16140
16153
|
"focus:outline-2 focus:outline-blue-500 focus:border-transparent",
|
|
16141
16154
|
"appearance-none",
|
|
16142
16155
|
disabled.value ? "outline-dashed text-gray-800 outline-2 -outline-offset-2 outline-gray-400 cursor-not-allowed border-transparent" : "bg-white cursor-pointer",
|
|
16143
|
-
isInvalid.value && !disabled.value && "outline-2 -outline-offset-2 outline-red-600 text-red-
|
|
16156
|
+
isInvalid.value && !disabled.value && "outline-2 -outline-offset-2 outline-red-600 text-red-700",
|
|
16144
16157
|
props.inputClass
|
|
16145
16158
|
]);
|
|
16146
16159
|
const internalValue = vue.computed({
|
|
@@ -16211,7 +16224,7 @@ const _hoisted_3$1 = { class: "relative" };
|
|
|
16211
16224
|
const _hoisted_4$1 = ["value"];
|
|
16212
16225
|
const _hoisted_5$1 = {
|
|
16213
16226
|
key: 2,
|
|
16214
|
-
class: "text-red-
|
|
16227
|
+
class: "text-red-700 text-right font-bold mt-1"
|
|
16215
16228
|
};
|
|
16216
16229
|
const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
|
|
16217
16230
|
...{
|
|
@@ -16228,13 +16241,15 @@ const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
|
|
|
16228
16241
|
modelModifiers: { default: () => ({}) },
|
|
16229
16242
|
dataTestid: { default: void 0 },
|
|
16230
16243
|
inputClass: { default: void 0 },
|
|
16244
|
+
maxlength: { default: void 0 },
|
|
16231
16245
|
value: { default: void 0 }
|
|
16232
16246
|
}, {
|
|
16233
16247
|
"modelValue": { default: void 0, required: false },
|
|
16234
16248
|
"modelModifiers": {}
|
|
16235
16249
|
}),
|
|
16236
|
-
emits: /* @__PURE__ */ vue.mergeModels(["input", "change", "update:value", "blur"], ["update:modelValue"]),
|
|
16250
|
+
emits: /* @__PURE__ */ vue.mergeModels(["input", "change", "update:value", "blur", "valid"], ["update:modelValue"]),
|
|
16237
16251
|
setup(__props, { emit: __emit }) {
|
|
16252
|
+
const { t } = useFdsI18n();
|
|
16238
16253
|
const modelValue = vue.useModel(__props, "modelValue");
|
|
16239
16254
|
const props = __props;
|
|
16240
16255
|
const emit = __emit;
|
|
@@ -16252,7 +16267,7 @@ const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
|
|
|
16252
16267
|
return eventHandlers;
|
|
16253
16268
|
});
|
|
16254
16269
|
const textareaAttrs = vue.computed(() => {
|
|
16255
|
-
const { class: _, id: _id, rows: _rows, ...rest } = attrs;
|
|
16270
|
+
const { class: _, id: _id, rows: _rows, maxlength: _maxlength, ...rest } = attrs;
|
|
16256
16271
|
const filtered = {};
|
|
16257
16272
|
for (const key in rest) {
|
|
16258
16273
|
if (!key.startsWith("on") || typeof rest[key] !== "function") {
|
|
@@ -16263,33 +16278,61 @@ const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
|
|
|
16263
16278
|
...filtered,
|
|
16264
16279
|
id: textareaId.value,
|
|
16265
16280
|
rows: rows.value ?? 4,
|
|
16266
|
-
"aria-invalid": props.valid === false ? true : void 0,
|
|
16281
|
+
"aria-invalid": props.valid === false || isOverMaxLength.value ? true : void 0,
|
|
16267
16282
|
"data-testid": props.dataTestid ?? void 0
|
|
16268
16283
|
};
|
|
16269
16284
|
});
|
|
16270
16285
|
const isLazy = vue.computed(() => props.modelModifiers?.lazy === true);
|
|
16286
|
+
const internalValue = vue.computed({
|
|
16287
|
+
get: () => modelValue.value !== void 0 ? modelValue.value : props.value ?? "",
|
|
16288
|
+
set: (newValue) => {
|
|
16289
|
+
if (modelValue.value !== void 0) {
|
|
16290
|
+
modelValue.value = newValue;
|
|
16291
|
+
}
|
|
16292
|
+
emit("update:value", newValue);
|
|
16293
|
+
}
|
|
16294
|
+
});
|
|
16295
|
+
const liveValue = vue.ref("");
|
|
16296
|
+
vue.watch(
|
|
16297
|
+
() => internalValue.value,
|
|
16298
|
+
(value) => {
|
|
16299
|
+
if (value !== liveValue.value) {
|
|
16300
|
+
liveValue.value = value;
|
|
16301
|
+
}
|
|
16302
|
+
},
|
|
16303
|
+
{ immediate: true }
|
|
16304
|
+
);
|
|
16271
16305
|
const showInvalidMessage = vue.computed(() => props.valid === false && !props.optional && props.invalidMessage);
|
|
16272
16306
|
const isInvalid = vue.computed(() => props.valid === false && !props.optional && !disabled.value);
|
|
16273
16307
|
const isValid2 = vue.computed(() => props.valid === true);
|
|
16308
|
+
const characterCount = vue.computed(() => liveValue.value.length);
|
|
16309
|
+
const showCharacterCount = vue.computed(() => props.maxlength != null);
|
|
16310
|
+
const isOverMaxLength = vue.computed(() => props.maxlength != null && characterCount.value > props.maxlength);
|
|
16311
|
+
const maxLengthValid = vue.computed(() => {
|
|
16312
|
+
if (props.maxlength == null) {
|
|
16313
|
+
return null;
|
|
16314
|
+
}
|
|
16315
|
+
return characterCount.value <= props.maxlength;
|
|
16316
|
+
});
|
|
16317
|
+
vue.watch(
|
|
16318
|
+
maxLengthValid,
|
|
16319
|
+
(value) => {
|
|
16320
|
+
emit("valid", value);
|
|
16321
|
+
},
|
|
16322
|
+
{ immediate: true }
|
|
16323
|
+
);
|
|
16274
16324
|
const inputClasses = vue.computed(() => [
|
|
16275
16325
|
"block w-full rounded-md border border-gray-500 px-3 py-2",
|
|
16276
16326
|
"focus:outline-2 focus:outline-blue-500 focus:border-transparent",
|
|
16277
16327
|
disabled.value ? "text-gray-800 outline-dashed outline-2 -outline-offset-2 outline-gray-400 cursor-not-allowed border-transparent bg-gray-50" : "bg-white",
|
|
16278
16328
|
isInvalid.value && "outline-2 -outline-offset-2 outline-red-600",
|
|
16329
|
+
isOverMaxLength.value && !disabled.value && "outline-2 -outline-offset-2 outline-red-600",
|
|
16279
16330
|
props.inputClass
|
|
16280
16331
|
]);
|
|
16281
16332
|
const validationIconClasses = vue.computed(() => ["absolute right-3 top-3 flex items-center gap-2 pointer-events-none"]);
|
|
16282
|
-
const internalValue = vue.computed({
|
|
16283
|
-
get: () => modelValue.value !== void 0 ? modelValue.value : props.value ?? "",
|
|
16284
|
-
set: (newValue) => {
|
|
16285
|
-
if (modelValue.value !== void 0) {
|
|
16286
|
-
modelValue.value = newValue;
|
|
16287
|
-
}
|
|
16288
|
-
emit("update:value", newValue);
|
|
16289
|
-
}
|
|
16290
|
-
});
|
|
16291
16333
|
function handleInputChange(ev) {
|
|
16292
16334
|
const target = ev.target;
|
|
16335
|
+
liveValue.value = target.value;
|
|
16293
16336
|
if (isLazy.value && ev.type === "input") {
|
|
16294
16337
|
return;
|
|
16295
16338
|
}
|
|
@@ -16313,7 +16356,7 @@ const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
|
|
|
16313
16356
|
__props.meta ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$1, vue.toDisplayString(__props.meta), 1)) : vue.createCommentVNode("", true),
|
|
16314
16357
|
vue.createElementVNode("div", _hoisted_3$1, [
|
|
16315
16358
|
vue.createElementVNode("textarea", vue.mergeProps({
|
|
16316
|
-
value:
|
|
16359
|
+
value: liveValue.value,
|
|
16317
16360
|
class: inputClasses.value
|
|
16318
16361
|
}, textareaAttrs.value, {
|
|
16319
16362
|
onInput: handleInputChange,
|
|
@@ -16334,7 +16377,10 @@ const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
|
|
|
16334
16377
|
})) : vue.createCommentVNode("", true)
|
|
16335
16378
|
], 2)
|
|
16336
16379
|
]),
|
|
16337
|
-
showInvalidMessage.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$1, vue.toDisplayString(__props.invalidMessage), 1)) : vue.
|
|
16380
|
+
showInvalidMessage.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$1, vue.toDisplayString(__props.invalidMessage), 1)) : showCharacterCount.value ? (vue.openBlock(), vue.createElementBlock("p", {
|
|
16381
|
+
key: 3,
|
|
16382
|
+
class: vue.normalizeClass(["mt-1 text-right font-bold", isOverMaxLength.value ? "text-red-700" : "text-gray-900"])
|
|
16383
|
+
}, vue.toDisplayString(characterCount.value) + " / " + vue.toDisplayString(__props.maxlength) + " " + vue.toDisplayString(vue.unref(t)("FdsTextarea.characters")), 3)) : vue.createCommentVNode("", true)
|
|
16338
16384
|
], 2);
|
|
16339
16385
|
};
|
|
16340
16386
|
}
|