@isoftdata/svelte-password-fields
Advanced tools
+216
-147
@@ -1,146 +0,212 @@ | ||
| <script>import Input from "@isoftdata/svelte-input"; | ||
| import Button from "@isoftdata/svelte-button"; | ||
| import { getContext } from "svelte"; | ||
| const i18next = getContext("i18next"); | ||
| const defaultTranslate = (_key, defaultString, replacementTokens) => { | ||
| if (replacementTokens && typeof replacementTokens === "object" && Object.keys(replacementTokens).length) { | ||
| return Object.entries(replacementTokens).reduce((acc, [key, value]) => { | ||
| return acc.replace(new RegExp(`{{${key}}}`, "g"), value.toString()); | ||
| }, defaultString); | ||
| } else { | ||
| return defaultString; | ||
| } | ||
| }; | ||
| const translate = typeof i18next?.t === "function" ? i18next.t : defaultTranslate; | ||
| const getUppercaseCharactersCount = (password2) => (password2.match(/[A-Z]/g) ?? []).length; | ||
| const getLowercaseCharactersCount = (password2) => (password2.match(/[a-z]/g) ?? []).length; | ||
| const getNumericCharacterCount = (password2) => (password2.match(/[0-9]/g) ?? []).length; | ||
| const getSpecialCharactersCount = (password2) => { | ||
| const uppercaseCharactersCount = getUppercaseCharactersCount(password2); | ||
| const lowercaseCharactersCount = getLowercaseCharactersCount(password2); | ||
| const numericCharactersCount = getNumericCharacterCount(password2); | ||
| return password2.length - uppercaseCharactersCount - lowercaseCharactersCount - numericCharactersCount; | ||
| }; | ||
| const validationEnforcementMap = /* @__PURE__ */ new Map([ | ||
| [ | ||
| "minimumPasswordLength", | ||
| { | ||
| translationKey: "passwordFields:rules.numberOfRequiredCharacters.lowercase", | ||
| defaultTranslation: `Password must be at least {{minimumPasswordLength}} characters long`, | ||
| isValid: (password2, { minimumPasswordLength }) => { | ||
| return !!(password2 && isNumber(minimumPasswordLength) && password2.length >= minimumPasswordLength); | ||
| } | ||
| } | ||
| ], | ||
| [ | ||
| "maximumPasswordLength", | ||
| { | ||
| translationKey: "passwordFields:rules.numberOfRequiredCharacters.uppercase", | ||
| defaultTranslation: `Password must be no more than {{maximumPasswordLength}} characters long`, | ||
| isValid: (password2, { maximumPasswordLength }) => { | ||
| return !!(password2 && isNumber(maximumPasswordLength) && password2.length <= maximumPasswordLength); | ||
| } | ||
| } | ||
| ], | ||
| [ | ||
| "numberOfRequiredLowercaseCharacters", | ||
| { | ||
| translationKey: "passwordFields:rules.numberOfRequiredCharacters.numeric", | ||
| defaultTranslation: `Password must contain at least {{numberOfRequiredLowercaseCharacters}} lowercase characters`, | ||
| isValid: (password2, { numberOfRequiredLowercaseCharacters }) => { | ||
| return !!(password2 && isNumber(numberOfRequiredLowercaseCharacters) && getLowercaseCharactersCount(password2) >= numberOfRequiredLowercaseCharacters); | ||
| } | ||
| } | ||
| ], | ||
| [ | ||
| "numberOfRequiredUppercaseCharacters", | ||
| { | ||
| translationKey: "passwordFields:rules.numberOfRequiredCharacters.special", | ||
| defaultTranslation: `Password must contain at least {{numberOfRequiredUppercaseCharacters}} uppercase characters`, | ||
| isValid: (password2, { numberOfRequiredUppercaseCharacters }) => { | ||
| return !!(password2 && isNumber(numberOfRequiredUppercaseCharacters) && getUppercaseCharactersCount(password2) >= numberOfRequiredUppercaseCharacters); | ||
| } | ||
| } | ||
| ], | ||
| [ | ||
| "numberOfRequiredNumericCharacters", | ||
| { | ||
| translationKey: "passwordFields:rules.minimumLength", | ||
| defaultTranslation: `Password must contain at least {{numberOfRequiredNumericCharacters}} numeric characters`, | ||
| isValid: (password2, { numberOfRequiredNumericCharacters }) => { | ||
| return !!(password2 && isNumber(numberOfRequiredNumericCharacters) && getNumericCharacterCount(password2) >= numberOfRequiredNumericCharacters); | ||
| } | ||
| } | ||
| ], | ||
| [ | ||
| "numberOfRequiredSpecialCharacters", | ||
| { | ||
| translationKey: "passwordFields:rules.maximumLength", | ||
| defaultTranslation: `Password must contain at least {{numberOfRequiredSpecialCharacters}} special characters`, | ||
| isValid: (password2, { numberOfRequiredSpecialCharacters }) => { | ||
| return !!(password2 && isNumber(numberOfRequiredSpecialCharacters) && getSpecialCharactersCount(password2) >= numberOfRequiredSpecialCharacters); | ||
| } | ||
| } | ||
| ] | ||
| ]); | ||
| export let password = ""; | ||
| export let confirmPassword = ""; | ||
| export let columnClass = "col-12 col-md-6"; | ||
| export let passwordLabel = translate("passwordFields:passwordLabel", "Password"); | ||
| export let confirmPasswordLabel = translate("passwordFields:confirmPasswordLabel", "Confirm Password"); | ||
| export let passwordMismatch = false; | ||
| export let validationRules = void 0; | ||
| export let showPasswordRules = false; | ||
| export let passwordValidationFailed = false; | ||
| export let passwordInput = void 0; | ||
| export let passwordConfirmInput = void 0; | ||
| export let passwordAutocomplete = void 0; | ||
| export let confirmPasswordAutocomplete = void 0; | ||
| export let passwordIsValid = false; | ||
| function checkForPasswordMismatch() { | ||
| if (password && confirmPassword && password !== confirmPassword) { | ||
| passwordMismatch = true; | ||
| } else if (password === confirmPassword) { | ||
| passwordMismatch = false; | ||
| } | ||
| } | ||
| const isNumber = (v) => typeof v === "number"; | ||
| const isDefined = (v) => typeof v !== "undefined"; | ||
| let enforcedValidationMessages = getEnforcedValidationMessages(validationRules, validationEnforcementMap); | ||
| function getEnforcedValidationMessages(validationRules2, validationEnforcementMap2) { | ||
| let validationMessages = []; | ||
| passwordValidationFailed = false; | ||
| if (isDefined(validationRules2)) { | ||
| const validationKeys = Object.keys(validationRules2); | ||
| validationKeys.forEach((key) => { | ||
| const { translationKey, defaultTranslation, isValid } = validationEnforcementMap2.get(key); | ||
| const passwordIsValid2 = isValid(password, validationRules2); | ||
| if (!passwordIsValid2) { | ||
| passwordValidationFailed = true; | ||
| } | ||
| const validationRulesValue = validationRules2[key]; | ||
| const translationReplacement = { [key]: validationRulesValue }; | ||
| validationMessages.push({ | ||
| message: translate(translationKey, defaultTranslation, translationReplacement), | ||
| isValid: passwordIsValid2 | ||
| }); | ||
| }); | ||
| } | ||
| return validationMessages; | ||
| } | ||
| $: | ||
| passwordIsValid = validationRules ? enforcedValidationMessages.every(({ isValid }) => isValid) : true; | ||
| <script lang="ts"> | ||
| import type { i18n } from 'i18next' | ||
| import type { HTMLInputAttributes } from 'svelte/elements' | ||
| import type { ValidationRules } from './' | ||
| import Input from '@isoftdata/svelte-input' | ||
| import Button from '@isoftdata/svelte-button' | ||
| import Icon from '@isoftdata/svelte-icon' | ||
| import { getContext } from 'svelte' | ||
| import { translate as defaultTranslate } from '@isoftdata/utility-string' | ||
| const { t: translate } = getContext<i18n>('i18next') || { t: defaultTranslate } | ||
| const getUppercaseCharactersCount = (password: string) => (password.match(/[A-Z]/g) ?? []).length | ||
| const getLowercaseCharactersCount = (password: string) => (password.match(/[a-z]/g) ?? []).length | ||
| const getNumericCharacterCount = (password: string) => (password.match(/[0-9]/g) ?? []).length | ||
| const getSpecialCharactersCount = (password: string) => { | ||
| const uppercaseCharactersCount = getUppercaseCharactersCount(password) | ||
| const lowercaseCharactersCount = getLowercaseCharactersCount(password) | ||
| const numericCharactersCount = getNumericCharacterCount(password) | ||
| return password.length - uppercaseCharactersCount - lowercaseCharactersCount - numericCharactersCount | ||
| } | ||
| interface ValidationRulesMapValue { | ||
| translationKey: string | ||
| defaultTranslation: string | ||
| isValid: (password: string, validationEnforcementMap: ValidationRules) => boolean | ||
| } | ||
| type ValidationEnforementMap = Map<keyof ValidationRules, ValidationRulesMapValue> | ||
| const validationEnforcementMap: ValidationEnforementMap = new Map([ | ||
| [ | ||
| 'minimumPasswordLength', | ||
| { | ||
| translationKey: 'passwordFields:rules.numberOfRequiredCharacters.lowercase', | ||
| defaultTranslation: `Password must be at least {{minimumPasswordLength}} characters long`, | ||
| isValid: (password: string, { minimumPasswordLength }: ValidationRules): boolean => { | ||
| return !!(password && isNumber(minimumPasswordLength) && password.length >= minimumPasswordLength) | ||
| }, | ||
| }, | ||
| ], | ||
| [ | ||
| 'maximumPasswordLength', | ||
| { | ||
| translationKey: 'passwordFields:rules.numberOfRequiredCharacters.uppercase', | ||
| defaultTranslation: `Password must be no more than {{maximumPasswordLength}} characters long`, | ||
| isValid: (password: string, { maximumPasswordLength }: ValidationRules): boolean => { | ||
| return !!(password && isNumber(maximumPasswordLength) && password.length <= maximumPasswordLength) | ||
| }, | ||
| }, | ||
| ], | ||
| [ | ||
| 'numberOfRequiredLowercaseCharacters', | ||
| { | ||
| translationKey: 'passwordFields:rules.numberOfRequiredCharacters.numeric', | ||
| defaultTranslation: `Password must contain at least {{numberOfRequiredLowercaseCharacters}} lowercase characters`, | ||
| isValid: (password: string, { numberOfRequiredLowercaseCharacters }: ValidationRules): boolean => { | ||
| return !!( | ||
| password && | ||
| isNumber(numberOfRequiredLowercaseCharacters) && | ||
| getLowercaseCharactersCount(password) >= numberOfRequiredLowercaseCharacters | ||
| ) | ||
| }, | ||
| }, | ||
| ], | ||
| [ | ||
| 'numberOfRequiredUppercaseCharacters', | ||
| { | ||
| translationKey: 'passwordFields:rules.numberOfRequiredCharacters.special', | ||
| defaultTranslation: `Password must contain at least {{numberOfRequiredUppercaseCharacters}} uppercase characters`, | ||
| isValid: (password: string, { numberOfRequiredUppercaseCharacters }: ValidationRules): boolean => { | ||
| return !!( | ||
| password && | ||
| isNumber(numberOfRequiredUppercaseCharacters) && | ||
| getUppercaseCharactersCount(password) >= numberOfRequiredUppercaseCharacters | ||
| ) | ||
| }, | ||
| }, | ||
| ], | ||
| [ | ||
| 'numberOfRequiredNumericCharacters', | ||
| { | ||
| translationKey: 'passwordFields:rules.minimumLength', | ||
| defaultTranslation: `Password must contain at least {{numberOfRequiredNumericCharacters}} numeric characters`, | ||
| isValid: (password: string, { numberOfRequiredNumericCharacters }: ValidationRules): boolean => { | ||
| return !!( | ||
| password && | ||
| isNumber(numberOfRequiredNumericCharacters) && | ||
| getNumericCharacterCount(password) >= numberOfRequiredNumericCharacters | ||
| ) | ||
| }, | ||
| }, | ||
| ], | ||
| [ | ||
| 'numberOfRequiredSpecialCharacters', | ||
| { | ||
| translationKey: 'passwordFields:rules.maximumLength', | ||
| defaultTranslation: `Password must contain at least {{numberOfRequiredSpecialCharacters}} special characters`, | ||
| isValid: (password: string, { numberOfRequiredSpecialCharacters }: ValidationRules): boolean => { | ||
| return !!( | ||
| password && | ||
| isNumber(numberOfRequiredSpecialCharacters) && | ||
| getSpecialCharactersCount(password) >= numberOfRequiredSpecialCharacters | ||
| ) | ||
| }, | ||
| }, | ||
| ], | ||
| ]) | ||
| interface Props { | ||
| password?: string | ||
| confirmPassword?: string | ||
| columnClass?: string | ||
| passwordLabel?: string | ||
| confirmPasswordLabel?: string | ||
| passwordMismatch?: boolean | ||
| validationRules?: ValidationRules | undefined | ||
| showPasswordRules?: boolean | ||
| passwordValidationFailed?: boolean | ||
| passwordInput?: HTMLInputElement | undefined | ||
| passwordConfirmInput?: HTMLInputElement | undefined | ||
| passwordAutocomplete?: HTMLInputAttributes['autocomplete'] | undefined | ||
| confirmPasswordAutocomplete?: HTMLInputAttributes['autocomplete'] | undefined | ||
| passwordIsValid?: boolean | ||
| } | ||
| let { | ||
| password = $bindable(''), | ||
| confirmPassword = $bindable(''), | ||
| columnClass = 'col-12 col-md-6', | ||
| passwordLabel = translate('passwordFields:passwordLabel', 'Password'), | ||
| confirmPasswordLabel = translate('passwordFields:confirmPasswordLabel', 'Confirm Password'), | ||
| passwordMismatch = $bindable(false), | ||
| validationRules = undefined, | ||
| showPasswordRules = $bindable(false), | ||
| passwordValidationFailed = $bindable(false), | ||
| passwordInput = $bindable(undefined), | ||
| passwordConfirmInput = $bindable(undefined), | ||
| passwordAutocomplete = undefined, | ||
| confirmPasswordAutocomplete = undefined, | ||
| passwordIsValid = $bindable(false), | ||
| }: Props = $props() | ||
| function checkForPasswordMismatch() { | ||
| if (password && confirmPassword && password !== confirmPassword) { | ||
| passwordMismatch = true | ||
| } else if (password === confirmPassword) { | ||
| passwordMismatch = false | ||
| } | ||
| } | ||
| const isNumber = (v: unknown): v is number => typeof v === 'number' | ||
| const isDefined = (v: ValidationRules | undefined): v is ValidationRules => typeof v !== 'undefined' | ||
| type ValidationRulesKeys = keyof ValidationRules | ||
| interface ValidationMessage { | ||
| message: string | ||
| isValid: boolean | ||
| } | ||
| // this handles the initial load of the component | ||
| let enforcedValidationMessages: ValidationMessage[] = $state( | ||
| getEnforcedValidationMessages(validationRules, validationEnforcementMap), | ||
| ) | ||
| function getEnforcedValidationMessages( | ||
| validationRules: ValidationRules | undefined, | ||
| validationEnforcementMap: ValidationEnforementMap, | ||
| ): ValidationMessage[] { | ||
| let validationMessages: ValidationMessage[] = [] | ||
| passwordValidationFailed = false | ||
| if (isDefined(validationRules)) { | ||
| const validationKeys = Object.keys(validationRules) as ValidationRulesKeys[] | ||
| validationKeys.forEach(key => { | ||
| const { translationKey, defaultTranslation, isValid } = validationEnforcementMap.get( | ||
| key, | ||
| ) as ValidationRulesMapValue | ||
| const passwordIsValid = isValid(password, validationRules) | ||
| if (!passwordIsValid) { | ||
| passwordValidationFailed = true | ||
| } | ||
| const validationRulesValue = validationRules[key] | ||
| const translationReplacement = { [key]: validationRulesValue } as Record<string, string | number> | ||
| validationMessages.push({ | ||
| message: translate(translationKey, defaultTranslation, translationReplacement), | ||
| isValid: passwordIsValid, | ||
| }) | ||
| }) | ||
| } | ||
| return validationMessages | ||
| } | ||
| $effect(() => { | ||
| passwordIsValid = validationRules ? enforcedValidationMessages.every(({ isValid }) => isValid) : true | ||
| }) | ||
| </script> | ||
| <div class="form-row"> | ||
| <div class="row"> | ||
| <div class={columnClass}> | ||
| <Input | ||
| bind:input={passwordInput} | ||
| class={passwordMismatch ? 'is-invalid' : ''} | ||
| bind:value={password} | ||
| class={{ 'is-invalid': passwordMismatch }} | ||
| label={passwordLabel} | ||
| bind:value={password} | ||
| autocomplete={passwordAutocomplete} | ||
| type="password" | ||
| required | ||
| on:change={() => { | ||
| onchange={() => { | ||
| checkForPasswordMismatch() | ||
@@ -151,3 +217,5 @@ if (passwordValidationFailed) { | ||
| }} | ||
| on:input={() => (enforcedValidationMessages = getEnforcedValidationMessages(validationRules, validationEnforcementMap))} | ||
| oninput={() => { | ||
| enforcedValidationMessages = getEnforcedValidationMessages(validationRules, validationEnforcementMap) | ||
| }} | ||
| /> | ||
@@ -157,7 +225,7 @@ {#if validationRules} | ||
| color="link" | ||
| tabIndex="-1" | ||
| tabindex={-1} | ||
| size="xs" | ||
| class="pl-0" | ||
| textClass="small" | ||
| on:click={() => (showPasswordRules = !showPasswordRules)}>Password Rules</Button | ||
| onclick={() => (showPasswordRules = !showPasswordRules)}>Password Rules</Button | ||
| > | ||
@@ -175,3 +243,3 @@ {/if} | ||
| required | ||
| on:change={checkForPasswordMismatch} | ||
| onchange={checkForPasswordMismatch} | ||
| /> | ||
@@ -184,9 +252,10 @@ </div> | ||
| <li> | ||
| <i | ||
| class="fas fa-fw" | ||
| class:fa-check={isValid} | ||
| class:fa-xmark={!isValid} | ||
| class:text-success={isValid} | ||
| class:text-danger={!isValid} | ||
| ></i> | ||
| <Icon | ||
| icon={isValid ? 'check' : 'xmark'} | ||
| fixedWidth | ||
| class={{ | ||
| 'text-success': isValid, | ||
| 'text-danger': !isValid, | ||
| }} | ||
| /> | ||
| {message} | ||
@@ -193,0 +262,0 @@ </li> |
@@ -1,31 +0,21 @@ | ||
| import { SvelteComponent } from "svelte"; | ||
| import type { HTMLInputAttributes } from 'svelte/elements'; | ||
| import type { ValidationRules } from './'; | ||
| declare const __propDef: { | ||
| props: { | ||
| password?: string | undefined; | ||
| confirmPassword?: string | undefined; | ||
| columnClass?: string | undefined; | ||
| passwordLabel?: string | undefined; | ||
| confirmPasswordLabel?: string | undefined; | ||
| passwordMismatch?: boolean | undefined; | ||
| validationRules?: ValidationRules | undefined; | ||
| showPasswordRules?: boolean | undefined; | ||
| passwordValidationFailed?: boolean | undefined; | ||
| passwordInput?: HTMLInputElement | undefined; | ||
| passwordConfirmInput?: HTMLInputElement | undefined; | ||
| passwordAutocomplete?: HTMLInputAttributes['autocomplete'] | undefined; | ||
| confirmPasswordAutocomplete?: HTMLInputAttributes['autocomplete'] | undefined; | ||
| passwordIsValid?: boolean | undefined; | ||
| }; | ||
| events: { | ||
| [evt: string]: CustomEvent<any>; | ||
| }; | ||
| slots: {}; | ||
| }; | ||
| export type PasswordFieldsProps = typeof __propDef.props; | ||
| export type PasswordFieldsEvents = typeof __propDef.events; | ||
| export type PasswordFieldsSlots = typeof __propDef.slots; | ||
| export default class PasswordFields extends SvelteComponent<PasswordFieldsProps, PasswordFieldsEvents, PasswordFieldsSlots> { | ||
| interface Props { | ||
| password?: string; | ||
| confirmPassword?: string; | ||
| columnClass?: string; | ||
| passwordLabel?: string; | ||
| confirmPasswordLabel?: string; | ||
| passwordMismatch?: boolean; | ||
| validationRules?: ValidationRules | undefined; | ||
| showPasswordRules?: boolean; | ||
| passwordValidationFailed?: boolean; | ||
| passwordInput?: HTMLInputElement | undefined; | ||
| passwordConfirmInput?: HTMLInputElement | undefined; | ||
| passwordAutocomplete?: HTMLInputAttributes['autocomplete'] | undefined; | ||
| confirmPasswordAutocomplete?: HTMLInputAttributes['autocomplete'] | undefined; | ||
| passwordIsValid?: boolean; | ||
| } | ||
| export {}; | ||
| declare const PasswordFields: import("svelte").Component<Props, {}, "password" | "confirmPassword" | "passwordMismatch" | "showPasswordRules" | "passwordValidationFailed" | "passwordInput" | "passwordConfirmInput" | "passwordIsValid">; | ||
| type PasswordFields = ReturnType<typeof PasswordFields>; | ||
| export default PasswordFields; |
+63
-56
| { | ||
| "name": "@isoftdata/svelte-password-fields", | ||
| "version": "1.5.0", | ||
| "scripts": { | ||
| "dev": "vite dev", | ||
| "build": "vite build && npm run package", | ||
| "preview": "vite preview", | ||
| "package": "svelte-kit sync && svelte-package && publint", | ||
| "prepublishOnly": "npm run package", | ||
| "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", | ||
| "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", | ||
| "lint": "prettier --check . && eslint .", | ||
| "format": "prettier --write ." | ||
| }, | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "svelte": "./dist/index.js" | ||
| } | ||
| }, | ||
| "files": [ | ||
| "dist", | ||
| "!dist/**/*.test.*", | ||
| "!dist/**/*.spec.*" | ||
| ], | ||
| "peerDependencies": { | ||
| "svelte": "^4.0.0 || ^5.1.6" | ||
| }, | ||
| "devDependencies": { | ||
| "@isoftdata/prettier-config": "^1.0.3", | ||
| "@sveltejs/adapter-auto": "^2.0.0", | ||
| "@sveltejs/kit": "^1.27.4", | ||
| "@sveltejs/package": "^2.0.0", | ||
| "@typescript-eslint/eslint-plugin": "^6.0.0", | ||
| "@typescript-eslint/parser": "^6.0.0", | ||
| "eslint": "^8.28.0", | ||
| "eslint-config-prettier": "^9.0.0", | ||
| "eslint-plugin-svelte": "^2.30.0", | ||
| "i18next": "^23.7.7", | ||
| "prettier": "^3.0.0", | ||
| "prettier-plugin-svelte": "^3.0.0", | ||
| "publint": "^0.1.9", | ||
| "svelte": "^4.2.7", | ||
| "svelte-check": "^3.6.0", | ||
| "tslib": "^2.4.1", | ||
| "typescript": "^5.0.0", | ||
| "vite": "^4.4.2" | ||
| }, | ||
| "svelte": "./dist/index.js", | ||
| "types": "./dist/index.d.ts", | ||
| "type": "module", | ||
| "prettier": "@isoftdata/prettier-config", | ||
| "dependencies": { | ||
| "@isoftdata/svelte-button": "^1.3.1", | ||
| "@isoftdata/svelte-input": "^1.2.1" | ||
| } | ||
| } | ||
| "name": "@isoftdata/svelte-password-fields", | ||
| "version": "2.0.0", | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "svelte": "./dist/index.js" | ||
| } | ||
| }, | ||
| "files": [ | ||
| "dist", | ||
| "!dist/**/*.test.*", | ||
| "!dist/**/*.spec.*" | ||
| ], | ||
| "peerDependencies": { | ||
| "svelte": "^5.23.2" | ||
| }, | ||
| "devDependencies": { | ||
| "@isoftdata/prettier-config": "^2.0.4", | ||
| "@isoftdata/svelte-bootstrap-version-switcher": "^1.1.2", | ||
| "@sveltejs/adapter-auto": "^6.0.0", | ||
| "@sveltejs/kit": "^2.20.8", | ||
| "@sveltejs/package": "^2.3.11", | ||
| "@sveltejs/vite-plugin-svelte": "^5.0.3", | ||
| "@typescript-eslint/eslint-plugin": "^6.21.0", | ||
| "@typescript-eslint/parser": "^6.21.0", | ||
| "eslint": "^8.57.1", | ||
| "eslint-config-prettier": "^9.1.0", | ||
| "eslint-plugin-svelte": "^2.46.1", | ||
| "i18next": "^23.16.8", | ||
| "prettier": "^3.5.3", | ||
| "prettier-plugin-svelte": "^3.3.3", | ||
| "publint": "^0.1.16", | ||
| "svelte": "^5.0.0", | ||
| "svelte-check": "^4.1.7", | ||
| "tslib": "^2.8.1", | ||
| "typescript": "^5.8.3", | ||
| "vite": "^6.3.4" | ||
| }, | ||
| "svelte": "./dist/index.js", | ||
| "types": "./dist/index.d.ts", | ||
| "type": "module", | ||
| "prettier": "@isoftdata/prettier-config", | ||
| "dependencies": { | ||
| "@isoftdata/svelte-button": "^2.1.0", | ||
| "@isoftdata/svelte-icon": "^2.0.1", | ||
| "@isoftdata/svelte-input": "^2.0.1", | ||
| "@isoftdata/utility-string": "^2.1.0", | ||
| "svelte": "^5.28.2" | ||
| }, | ||
| "engines": { | ||
| "pnpm": "10.x" | ||
| }, | ||
| "scripts": { | ||
| "dev": "vite dev", | ||
| "build": "vite build && npm run package", | ||
| "preview": "vite preview", | ||
| "package": "svelte-kit sync && svelte-package && publint", | ||
| "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", | ||
| "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", | ||
| "lint": "prettier --check . && eslint .", | ||
| "format": "prettier --write ." | ||
| } | ||
| } |
+6
-1
@@ -8,5 +8,10 @@ # Svelte PasswordFields | ||
| ```sh | ||
| npm i @isoftdata/svelte-password-fields | ||
| pnpm i @isoftdata/svelte-password-fields | ||
| ``` | ||
| ## Breaking changes | ||
| ### 2.0.0 | ||
| - Require Svelte 5 | ||
| ## Props | ||
@@ -13,0 +18,0 @@ |
15576
9.98%79
6.76%6
100%20
11.11%35
-22.22%+ Added
+ Added
+ Added
- Removed