@umbra.ui/core 0.1.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/components/controls/Dropdown/types.d.ts +5 -0
- package/dist/components/controls/Dropdown/types.d.ts.map +1 -0
- package/dist/components/controls/Dropdown/types.js +1 -0
- package/dist/components/controls/SegmentedControl/types.d.ts +6 -0
- package/dist/components/controls/SegmentedControl/types.d.ts.map +1 -0
- package/dist/components/controls/SegmentedControl/types.js +1 -0
- package/dist/components/dialogs/Alert/types.d.ts +7 -0
- package/dist/components/dialogs/Alert/types.d.ts.map +1 -0
- package/dist/components/dialogs/Alert/types.js +1 -0
- package/dist/components/dialogs/Toast/types.d.ts +34 -0
- package/dist/components/dialogs/Toast/types.d.ts.map +1 -0
- package/dist/components/dialogs/Toast/types.js +10 -0
- package/dist/components/dialogs/Toast/useToast.d.ts +36 -0
- package/dist/components/dialogs/Toast/useToast.d.ts.map +1 -0
- package/dist/components/dialogs/Toast/useToast.js +90 -0
- package/dist/components/indicators/Tooltip/tooltip.d.ts +3 -0
- package/dist/components/indicators/Tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/tooltip.js +33 -0
- package/dist/components/indicators/Tooltip/types.d.ts +14 -0
- package/dist/components/indicators/Tooltip/types.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/types.js +1 -0
- package/dist/components/indicators/Tooltip/useTooltip.d.ts +18 -0
- package/dist/components/indicators/Tooltip/useTooltip.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/useTooltip.js +57 -0
- package/dist/components/inputs/Tags/tag-bar-styles.d.ts +14 -0
- package/dist/components/inputs/Tags/tag-bar-styles.d.ts.map +1 -0
- package/dist/components/inputs/Tags/tag-bar-styles.js +313 -0
- package/dist/components/inputs/Tags/types.d.ts +93 -0
- package/dist/components/inputs/Tags/types.d.ts.map +1 -0
- package/dist/components/inputs/Tags/types.js +216 -0
- package/dist/components/inputs/search/types.d.ts +9 -0
- package/dist/components/inputs/search/types.d.ts.map +1 -0
- package/dist/components/inputs/search/types.js +1 -0
- package/dist/components/navigation/adaptive/types.d.ts +16 -0
- package/dist/components/navigation/adaptive/types.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/types.js +1 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts +27 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.js +40 -0
- package/dist/components/navigation/adaptive/useBreakpoints.d.ts +6 -0
- package/dist/components/navigation/adaptive/useBreakpoints.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useBreakpoints.js +37 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.d.ts +93 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.js +145 -0
- package/dist/components/navigation/adaptive/useViewAnimation.d.ts +31 -0
- package/dist/components/navigation/adaptive/useViewAnimation.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useViewAnimation.js +591 -0
- package/dist/components/navigation/adaptive/useViewResize.d.ts +52 -0
- package/dist/components/navigation/adaptive/useViewResize.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useViewResize.js +146 -0
- package/dist/components/navigation/navstack/useNavigationStack.d.ts +25 -0
- package/dist/components/navigation/navstack/useNavigationStack.d.ts.map +1 -0
- package/dist/components/navigation/navstack/useNavigationStack.js +133 -0
- package/dist/components/navigation/slideover/useSlideoverController.d.ts +20 -0
- package/dist/components/navigation/slideover/useSlideoverController.d.ts.map +1 -0
- package/dist/components/navigation/slideover/useSlideoverController.js +267 -0
- package/dist/components/navigation/splitview/useSplitViewController.d.ts +20 -0
- package/dist/components/navigation/splitview/useSplitViewController.d.ts.map +1 -0
- package/dist/components/navigation/splitview/useSplitViewController.js +325 -0
- package/dist/components/navigation/tabcontroller/types.d.ts +21 -0
- package/dist/components/navigation/tabcontroller/types.d.ts.map +1 -0
- package/dist/components/navigation/tabcontroller/types.js +1 -0
- package/dist/components/navigation/tabcontroller/useTabController.d.ts +5 -0
- package/dist/components/navigation/tabcontroller/useTabController.d.ts.map +1 -0
- package/dist/components/navigation/tabcontroller/useTabController.js +10 -0
- package/dist/components/navigation/types.d.ts +8 -0
- package/dist/components/navigation/types.d.ts.map +1 -0
- package/dist/components/navigation/types.js +1 -0
- package/dist/components/pickers/CollectionPicker/types.d.ts +11 -0
- package/dist/components/pickers/CollectionPicker/types.d.ts.map +1 -0
- package/dist/components/pickers/CollectionPicker/types.js +1 -0
- package/dist/components/pickers/ColorPicker/colors.d.ts +13 -0
- package/dist/components/pickers/ColorPicker/colors.d.ts.map +1 -0
- package/dist/components/pickers/ColorPicker/colors.js +266 -0
- package/dist/components/pickers/FilePicker/types.d.ts +10 -0
- package/dist/components/pickers/FilePicker/types.d.ts.map +1 -0
- package/dist/components/pickers/FilePicker/types.js +1 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +196 -0
- package/dist/theme.d.ts +73 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +279 -0
- package/dist/themes/blank.d.ts +7 -0
- package/dist/themes/blank.d.ts.map +1 -0
- package/dist/themes/blank.js +543 -0
- package/dist/themes/crimson-dark.d.ts +4 -0
- package/dist/themes/crimson-dark.d.ts.map +1 -0
- package/dist/themes/crimson-dark.js +552 -0
- package/dist/themes/cyan-light.d.ts +4 -0
- package/dist/themes/cyan-light.d.ts.map +1 -0
- package/dist/themes/cyan-light.js +552 -0
- package/dist/themes/dark.d.ts +4 -0
- package/dist/themes/dark.d.ts.map +1 -0
- package/dist/themes/dark.js +551 -0
- package/dist/themes/gold-dark.d.ts +4 -0
- package/dist/themes/gold-dark.d.ts.map +1 -0
- package/dist/themes/gold-dark.js +552 -0
- package/dist/themes/grass-dark.d.ts +4 -0
- package/dist/themes/grass-dark.d.ts.map +1 -0
- package/dist/themes/grass-dark.js +552 -0
- package/dist/themes/indigo.d.ts +4 -0
- package/dist/themes/indigo.d.ts.map +1 -0
- package/dist/themes/indigo.js +552 -0
- package/dist/themes/light.d.ts +4 -0
- package/dist/themes/light.d.ts.map +1 -0
- package/dist/themes/light.js +551 -0
- package/dist/themes/orange-dark.d.ts +4 -0
- package/dist/themes/orange-dark.d.ts.map +1 -0
- package/dist/themes/orange-dark.js +551 -0
- package/dist/themes/orange-light.d.ts +4 -0
- package/dist/themes/orange-light.d.ts.map +1 -0
- package/dist/themes/orange-light.js +551 -0
- package/package.json +62 -0
- package/src/components/controls/Button/Button.vue +417 -0
- package/src/components/controls/Button/README.md +348 -0
- package/src/components/controls/Button/theme.css +200 -0
- package/src/components/controls/Checkbox/Checkbox.vue +164 -0
- package/src/components/controls/Checkbox/README.md +441 -0
- package/src/components/controls/Checkbox/theme.css +36 -0
- package/src/components/controls/Dropdown/Dropdown.vue +476 -0
- package/src/components/controls/Dropdown/README.md +370 -0
- package/src/components/controls/Dropdown/theme.css +50 -0
- package/src/components/controls/Dropdown/types.ts +6 -0
- package/src/components/controls/IconButton/IconButton.vue +267 -0
- package/src/components/controls/IconButton/README.md +502 -0
- package/src/components/controls/IconButton/theme.css +89 -0
- package/src/components/controls/Radio/README.md +591 -0
- package/src/components/controls/Radio/Radio.vue +89 -0
- package/src/components/controls/Radio/theme.css +14 -0
- package/src/components/controls/RangeSlider/README.md +608 -0
- package/src/components/controls/RangeSlider/RangeSlider.vue +535 -0
- package/src/components/controls/RangeSlider/theme.css +80 -0
- package/src/components/controls/SegmentedControl/README.md +587 -0
- package/src/components/controls/SegmentedControl/SegmentedControl.vue +284 -0
- package/src/components/controls/SegmentedControl/theme.css +60 -0
- package/src/components/controls/SegmentedControl/types.ts +5 -0
- package/src/components/controls/Slider/README.md +627 -0
- package/src/components/controls/Slider/Slider.vue +260 -0
- package/src/components/controls/Slider/theme.css +74 -0
- package/src/components/controls/Stepper/README.md +601 -0
- package/src/components/controls/Stepper/Stepper.vue +103 -0
- package/src/components/controls/Stepper/theme.css +53 -0
- package/src/components/controls/Switch/README.md +667 -0
- package/src/components/controls/Switch/Switch.vue +127 -0
- package/src/components/controls/Switch/theme.css +42 -0
- package/src/components/dialogs/Alert/Alert.vue +218 -0
- package/src/components/dialogs/Alert/README.md +450 -0
- package/src/components/dialogs/Alert/theme.css +44 -0
- package/src/components/dialogs/Alert/types.ts +11 -0
- package/src/components/dialogs/Toast/README.md +522 -0
- package/src/components/dialogs/Toast/Toast.vue +296 -0
- package/src/components/dialogs/Toast/ToastContainer.vue +330 -0
- package/src/components/dialogs/Toast/theme.css +44 -0
- package/src/components/dialogs/Toast/types.ts +46 -0
- package/src/components/dialogs/Toast/useToast.ts +127 -0
- package/src/components/indicators/ProgressBar/ProgressBar.vue +98 -0
- package/src/components/indicators/ProgressBar/README.md +744 -0
- package/src/components/indicators/ProgressBar/theme.css +36 -0
- package/src/components/indicators/Tooltip/README.md +723 -0
- package/src/components/indicators/Tooltip/TooltipProvider.vue +142 -0
- package/src/components/indicators/Tooltip/theme.css +18 -0
- package/src/components/indicators/Tooltip/tooltip.ts +48 -0
- package/src/components/indicators/Tooltip/types.ts +15 -0
- package/src/components/indicators/Tooltip/useTooltip.ts +71 -0
- package/src/components/inputs/AutogrowTextView/AutogrowTextView.vue +110 -0
- package/src/components/inputs/AutogrowTextView/README.md +643 -0
- package/src/components/inputs/AutogrowTextView/theme.css +28 -0
- package/src/components/inputs/InputCard/InputCard.vue +600 -0
- package/src/components/inputs/InputCard/README.md +636 -0
- package/src/components/inputs/InputEmail/InputEmail.vue +698 -0
- package/src/components/inputs/InputEmail/README.md +764 -0
- package/src/components/inputs/InputNumber/InputNumber.vue +300 -0
- package/src/components/inputs/InputNumber/README.md +749 -0
- package/src/components/inputs/InputPhone/InputPhone.vue +645 -0
- package/src/components/inputs/InputPhone/README.md +636 -0
- package/src/components/inputs/InputSecure/InputSecure.vue +646 -0
- package/src/components/inputs/InputSecure/README.md +771 -0
- package/src/components/inputs/InputText/InputText.vue +225 -0
- package/src/components/inputs/InputText/README.md +844 -0
- package/src/components/inputs/OTP/OTP.vue +349 -0
- package/src/components/inputs/OTP/README.md +736 -0
- package/src/components/inputs/OTP/theme.css +50 -0
- package/src/components/inputs/StringCapture/README.md +718 -0
- package/src/components/inputs/StringCapture/StringCapture.vue +315 -0
- package/src/components/inputs/StringCapture/theme.css +86 -0
- package/src/components/inputs/Tags/README.md +897 -0
- package/src/components/inputs/Tags/TagBar.vue +793 -0
- package/src/components/inputs/Tags/TagCreation.vue +219 -0
- package/src/components/inputs/Tags/TagPicker.vue +380 -0
- package/src/components/inputs/Tags/tag-bar-styles.ts +354 -0
- package/src/components/inputs/Tags/theme.css +121 -0
- package/src/components/inputs/Tags/types.ts +346 -0
- package/src/components/inputs/search/README.md +759 -0
- package/src/components/inputs/search/SearchBar.vue +394 -0
- package/src/components/inputs/search/SearchResults.vue +310 -0
- package/src/components/inputs/search/theme.css +187 -0
- package/src/components/inputs/search/types.ts +8 -0
- package/src/components/inputs/theme.css +102 -0
- package/src/components/menus/ActionMenu/ActionMenu.vue +383 -0
- package/src/components/menus/ActionMenu/README.md +825 -0
- package/src/components/menus/ActionMenu/theme.css +93 -0
- package/src/components/models/Popover/Popover.vue +551 -0
- package/src/components/models/Popover/README.md +885 -0
- package/src/components/models/Popover/theme.css +52 -0
- package/src/components/models/Sheet/README.md +1159 -0
- package/src/components/models/Sheet/Sheet.vue +465 -0
- package/src/components/models/Sheet/theme.css +72 -0
- package/src/components/models/Sidebar/README.md +1228 -0
- package/src/components/models/Sidebar/Sidebar.vue +480 -0
- package/src/components/models/Sidebar/theme.css +90 -0
- package/src/components/navigation/adaptive/AdaptiveLayout.vue +779 -0
- package/src/components/navigation/adaptive/AdaptiveLayoutBreadcrumbs.vue +192 -0
- package/src/components/navigation/adaptive/AdaptiveLayoutMenuButton.vue +149 -0
- package/src/components/navigation/adaptive/README.md +768 -0
- package/src/components/navigation/adaptive/types.ts +19 -0
- package/src/components/navigation/adaptive/useAdaptiveLayout.ts +89 -0
- package/src/components/navigation/adaptive/useBreakpoints.ts +41 -0
- package/src/components/navigation/adaptive/useContainerMonitor.ts +214 -0
- package/src/components/navigation/adaptive/useViewAnimation.ts +721 -0
- package/src/components/navigation/adaptive/useViewResize.ts +211 -0
- package/src/components/navigation/navstack/NavigationStack.vue +180 -0
- package/src/components/navigation/navstack/README.md +994 -0
- package/src/components/navigation/navstack/useNavigationStack.ts +164 -0
- package/src/components/navigation/slideover/README.md +1275 -0
- package/src/components/navigation/slideover/SlideoverController.vue +287 -0
- package/src/components/navigation/slideover/useSlideoverController.ts +320 -0
- package/src/components/navigation/splitview/README.md +1115 -0
- package/src/components/navigation/splitview/SplitViewController.vue +176 -0
- package/src/components/navigation/splitview/useSplitViewController.ts +388 -0
- package/src/components/navigation/tabcontroller/README.md +919 -0
- package/src/components/navigation/tabcontroller/TabController.vue +307 -0
- package/src/components/navigation/tabcontroller/TabItem.vue +57 -0
- package/src/components/navigation/tabcontroller/types.ts +24 -0
- package/src/components/navigation/tabcontroller/useTabController.ts +18 -0
- package/src/components/navigation/theme.css +91 -0
- package/src/components/navigation/types.ts +7 -0
- package/src/components/pickers/CollectionPicker/CollectionPicker.vue +398 -0
- package/src/components/pickers/CollectionPicker/README.md +1115 -0
- package/src/components/pickers/CollectionPicker/theme.css +14 -0
- package/src/components/pickers/CollectionPicker/types.ts +11 -0
- package/src/components/pickers/ColorPicker/ColorPicker.vue +376 -0
- package/src/components/pickers/ColorPicker/README.md +1439 -0
- package/src/components/pickers/ColorPicker/colors.ts +299 -0
- package/src/components/pickers/ColorPicker/theme.css +32 -0
- package/src/components/pickers/DatePicker/DatePicker.vue +660 -0
- package/src/components/pickers/DatePicker/README.md +1195 -0
- package/src/components/pickers/DatePicker/theme.css +22 -0
- package/src/components/pickers/FilePicker/FilePicker.vue +534 -0
- package/src/components/pickers/FilePicker/README.md +1542 -0
- package/src/components/pickers/FilePicker/theme.css +48 -0
- package/src/components/pickers/FilePicker/types.ts +10 -0
- package/src/components/pickers/IconPicker/IconPicker.vue +327 -0
- package/src/components/pickers/IconPicker/README.md +1161 -0
- package/src/components/pickers/IconPicker/theme.css +28 -0
- package/src/components/pickers/theme.css +82 -0
- package/src/components/views/MarkdownViewer/MarkdownViewer.vue +442 -0
- package/src/components/views/MarkdownViewer/README.md +833 -0
- package/src/components/views/MarkdownViewer/theme.css +130 -0
- package/src/index.ts +263 -0
- package/src/theme.ts +378 -0
- package/src/themes/crimson-dark.ts +556 -0
- package/src/themes/cyan-light.ts +556 -0
- package/src/themes/dark.ts +557 -0
- package/src/themes/gold-dark.ts +556 -0
- package/src/themes/grass-dark.ts +556 -0
- package/src/themes/indigo.ts +556 -0
- package/src/themes/light.ts +557 -0
- package/src/themes/orange-dark.ts +557 -0
- package/src/themes/orange-light.ts +557 -0
- package/src/vue.d.ts +45 -0
|
@@ -0,0 +1,771 @@
|
|
|
1
|
+
# InputSecure
|
|
2
|
+
|
|
3
|
+
A comprehensive password input component built with Vue 3 Composition API and TypeScript. The InputSecure component provides password visibility toggle, strength validation, requirement checking, secure password generation, and copy functionality with smooth animations and accessibility features.
|
|
4
|
+
|
|
5
|
+
## Installation/Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { InputSecure } from "@umbra-ui/core";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**Dependencies:**
|
|
12
|
+
|
|
13
|
+
- Vue 3.x
|
|
14
|
+
- @umbra-ui/icons (for eye, eye-slash, clone, and password edit icons)
|
|
15
|
+
|
|
16
|
+
## Basic Usage
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
import { ref } from "vue";
|
|
21
|
+
import { InputSecure } from "@umbra-ui/core";
|
|
22
|
+
|
|
23
|
+
const password = ref("");
|
|
24
|
+
|
|
25
|
+
const handlePasswordUpdate = (value: string) => {
|
|
26
|
+
console.log("Password:", value);
|
|
27
|
+
password.value = value;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const handleValidUpdate = (isValid: boolean) => {
|
|
31
|
+
console.log("Valid:", isValid);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const handleStrengthUpdate = (strength: number) => {
|
|
35
|
+
console.log("Strength:", strength);
|
|
36
|
+
};
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<div>
|
|
41
|
+
<InputSecure
|
|
42
|
+
v-model:value="password"
|
|
43
|
+
@update:valid="handleValidUpdate"
|
|
44
|
+
@update:strength="handleStrengthUpdate"
|
|
45
|
+
placeholder="Enter password"
|
|
46
|
+
:show-strength="true"
|
|
47
|
+
:allow-generate="true"
|
|
48
|
+
:show-requirements="true"
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Props
|
|
55
|
+
|
|
56
|
+
| Prop Name | Type | Required | Default | Description |
|
|
57
|
+
| --------------------- | ------------------------------------------------------------- | -------- | ------------------ | ------------------------------------------- |
|
|
58
|
+
| `value` | `string` | No | `""` | The password value |
|
|
59
|
+
| `placeholder` | `string` | No | `"Enter password"` | Placeholder text displayed when empty |
|
|
60
|
+
| `showStrength` | `boolean` | No | `true` | Whether to show password strength indicator |
|
|
61
|
+
| `allowGenerate` | `boolean` | No | `true` | Whether to show password generation button |
|
|
62
|
+
| `showRequirements` | `boolean` | No | `true` | Whether to show password requirements list |
|
|
63
|
+
| `minLength` | `number` | No | `8` | Minimum password length |
|
|
64
|
+
| `requireUppercase` | `boolean` | No | `true` | Whether to require uppercase letters |
|
|
65
|
+
| `requireLowercase` | `boolean` | No | `true` | Whether to require lowercase letters |
|
|
66
|
+
| `requireNumbers` | `boolean` | No | `true` | Whether to require numbers |
|
|
67
|
+
| `requireSpecialChars` | `boolean` | No | `true` | Whether to require special characters |
|
|
68
|
+
| `preventCommon` | `boolean` | No | `true` | Whether to prevent common passwords |
|
|
69
|
+
| `state` | `"normal" \| "active" \| "disabled" \| "readonly" \| "error"` | No | `"normal"` | Current state of the input field |
|
|
70
|
+
|
|
71
|
+
## Events
|
|
72
|
+
|
|
73
|
+
| Event Name | Payload Type | Description |
|
|
74
|
+
| ----------------- | ------------ | ------------------------------------------------ |
|
|
75
|
+
| `update:value` | `string` | Emitted when the password value changes |
|
|
76
|
+
| `update:valid` | `boolean` | Emitted when the validation state changes |
|
|
77
|
+
| `update:strength` | `number` | Emitted when the password strength changes (0-4) |
|
|
78
|
+
|
|
79
|
+
## Slots
|
|
80
|
+
|
|
81
|
+
This component does not provide any slots.
|
|
82
|
+
|
|
83
|
+
## Exposed Methods/Refs
|
|
84
|
+
|
|
85
|
+
This component does not expose any methods or refs.
|
|
86
|
+
|
|
87
|
+
## CSS Customization
|
|
88
|
+
|
|
89
|
+
The InputSecure component uses CSS custom properties for theming and customization:
|
|
90
|
+
|
|
91
|
+
### Input Container Variables
|
|
92
|
+
|
|
93
|
+
```css
|
|
94
|
+
--input-border: 1px solid var(--input-border-color);
|
|
95
|
+
--input-border-radius: 0.588rem;
|
|
96
|
+
--input-focus-border: var(--input-focus-color);
|
|
97
|
+
--input-background-normal: var(--input-bg-normal);
|
|
98
|
+
--input-background-filled: var(--input-bg-filled);
|
|
99
|
+
--input-border-filled: var(--input-border-filled-color);
|
|
100
|
+
--input-text-empty: var(--input-text-empty-color);
|
|
101
|
+
--input-text-filled: var(--input-text-filled-color);
|
|
102
|
+
--input-placeholder: var(--input-placeholder-color);
|
|
103
|
+
--input-placeholder-filled: var(--input-placeholder-filled-color);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### State-Specific Variables
|
|
107
|
+
|
|
108
|
+
```css
|
|
109
|
+
/* Disabled State */
|
|
110
|
+
--input-disabled-bg: var(--input-disabled-background);
|
|
111
|
+
--input-disabled-text: var(--input-disabled-text-color);
|
|
112
|
+
--input-disabled-border: var(--input-disabled-border-color);
|
|
113
|
+
--input-disabled-placeholder: var(--input-disabled-placeholder-color);
|
|
114
|
+
|
|
115
|
+
/* Readonly State */
|
|
116
|
+
--input-readonly-bg: var(--input-readonly-background);
|
|
117
|
+
--input-readonly-text: var(--input-readonly-text-color);
|
|
118
|
+
--input-readonly-border: var(--input-readonly-border-color);
|
|
119
|
+
--input-readonly-placeholder: var(--input-readonly-placeholder-color);
|
|
120
|
+
|
|
121
|
+
/* Error State */
|
|
122
|
+
--input-error-bg: var(--input-error-background);
|
|
123
|
+
--input-error-text: var(--input-error-text-color);
|
|
124
|
+
--input-error-border: var(--input-error-border-color);
|
|
125
|
+
|
|
126
|
+
/* Success State */
|
|
127
|
+
--input-success-color: var(--input-success-text-color);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Key Features
|
|
131
|
+
|
|
132
|
+
### Password Visibility
|
|
133
|
+
|
|
134
|
+
- **Toggle Visibility**: Show/hide password with eye icon toggle
|
|
135
|
+
- **Secure by Default**: Password is hidden by default
|
|
136
|
+
- **Accessibility**: Proper ARIA labels and keyboard navigation
|
|
137
|
+
|
|
138
|
+
### Password Strength
|
|
139
|
+
|
|
140
|
+
- **Real-time Assessment**: Calculates strength as user types (0-4 scale)
|
|
141
|
+
- **Visual Indicator**: Color-coded strength bar with labels
|
|
142
|
+
- **Strength Levels**: Very Weak, Weak, Fair, Good, Strong
|
|
143
|
+
- **Multiple Factors**: Length, character variety, pattern detection
|
|
144
|
+
|
|
145
|
+
### Password Requirements
|
|
146
|
+
|
|
147
|
+
- **Configurable Rules**: Customizable password requirements
|
|
148
|
+
- **Real-time Validation**: Shows requirement status as user types
|
|
149
|
+
- **Visual Feedback**: Checkmarks for met requirements
|
|
150
|
+
- **Common Password Prevention**: Blocks common weak passwords
|
|
151
|
+
|
|
152
|
+
### Password Generation
|
|
153
|
+
|
|
154
|
+
- **Secure Generation**: Creates cryptographically secure passwords
|
|
155
|
+
- **Requirement Compliance**: Generated passwords meet all requirements
|
|
156
|
+
- **Customizable Length**: Respects minimum length and requirements
|
|
157
|
+
- **Character Variety**: Includes all required character types
|
|
158
|
+
|
|
159
|
+
### Additional Features
|
|
160
|
+
|
|
161
|
+
- **Copy to Clipboard**: One-click password copying
|
|
162
|
+
- **Input States**: Normal, disabled, readonly, error states
|
|
163
|
+
- **Responsive Design**: Mobile-friendly with proper font scaling
|
|
164
|
+
- **Smooth Animations**: Transitions for requirements and strength indicators
|
|
165
|
+
|
|
166
|
+
## Examples
|
|
167
|
+
|
|
168
|
+
### Basic Password Input
|
|
169
|
+
|
|
170
|
+
```vue
|
|
171
|
+
<script setup lang="ts">
|
|
172
|
+
import { ref } from "vue";
|
|
173
|
+
import { InputSecure } from "@umbra-ui/core";
|
|
174
|
+
|
|
175
|
+
const password = ref("");
|
|
176
|
+
const isValid = ref(false);
|
|
177
|
+
const strength = ref(0);
|
|
178
|
+
|
|
179
|
+
const handleValidUpdate = (valid: boolean) => {
|
|
180
|
+
isValid.value = valid;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const handleStrengthUpdate = (strengthValue: number) => {
|
|
184
|
+
strength.value = strengthValue;
|
|
185
|
+
};
|
|
186
|
+
</script>
|
|
187
|
+
|
|
188
|
+
<template>
|
|
189
|
+
<div class="password-form">
|
|
190
|
+
<h3>Create Account</h3>
|
|
191
|
+
|
|
192
|
+
<div class="form-group">
|
|
193
|
+
<label>Password</label>
|
|
194
|
+
<InputSecure
|
|
195
|
+
v-model:value="password"
|
|
196
|
+
@update:valid="handleValidUpdate"
|
|
197
|
+
@update:strength="handleStrengthUpdate"
|
|
198
|
+
placeholder="Enter your password"
|
|
199
|
+
:show-strength="true"
|
|
200
|
+
:allow-generate="true"
|
|
201
|
+
:show-requirements="true"
|
|
202
|
+
/>
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<div class="password-info">
|
|
206
|
+
<p><strong>Valid:</strong> {{ isValid ? "Yes" : "No" }}</p>
|
|
207
|
+
<p><strong>Strength:</strong> {{ strength }}/4</p>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
</template>
|
|
211
|
+
|
|
212
|
+
<style module>
|
|
213
|
+
.password-form {
|
|
214
|
+
max-width: 400px;
|
|
215
|
+
padding: 1.5rem;
|
|
216
|
+
border: 1px solid #e0e0e0;
|
|
217
|
+
border-radius: 0.5rem;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.form-group {
|
|
221
|
+
margin-bottom: 1rem;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.form-group label {
|
|
225
|
+
display: block;
|
|
226
|
+
margin-bottom: 0.5rem;
|
|
227
|
+
font-weight: 500;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.password-info {
|
|
231
|
+
margin-top: 1rem;
|
|
232
|
+
padding: 1rem;
|
|
233
|
+
background-color: #f5f5f5;
|
|
234
|
+
border-radius: 0.25rem;
|
|
235
|
+
}
|
|
236
|
+
</style>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Custom Requirements
|
|
240
|
+
|
|
241
|
+
```vue
|
|
242
|
+
<script setup lang="ts">
|
|
243
|
+
import { ref } from "vue";
|
|
244
|
+
import { InputSecure } from "@umbra-ui/core";
|
|
245
|
+
|
|
246
|
+
const customPassword = ref("");
|
|
247
|
+
|
|
248
|
+
const handleCustomValid = (valid: boolean) => {
|
|
249
|
+
console.log("Custom password valid:", valid);
|
|
250
|
+
};
|
|
251
|
+
</script>
|
|
252
|
+
|
|
253
|
+
<template>
|
|
254
|
+
<div class="custom-requirements">
|
|
255
|
+
<h3>Custom Password Requirements</h3>
|
|
256
|
+
|
|
257
|
+
<div class="form-group">
|
|
258
|
+
<label>Password (Min 12 chars, no special chars required)</label>
|
|
259
|
+
<InputSecure
|
|
260
|
+
v-model:value="customPassword"
|
|
261
|
+
@update:valid="handleCustomValid"
|
|
262
|
+
placeholder="Enter password"
|
|
263
|
+
:min-length="12"
|
|
264
|
+
:require-uppercase="true"
|
|
265
|
+
:require-lowercase="true"
|
|
266
|
+
:require-numbers="true"
|
|
267
|
+
:require-special-chars="false"
|
|
268
|
+
:prevent-common="true"
|
|
269
|
+
:show-strength="true"
|
|
270
|
+
:show-requirements="true"
|
|
271
|
+
/>
|
|
272
|
+
</div>
|
|
273
|
+
|
|
274
|
+
<div class="requirements-info">
|
|
275
|
+
<h4>Custom Requirements:</h4>
|
|
276
|
+
<ul>
|
|
277
|
+
<li>At least 12 characters</li>
|
|
278
|
+
<li>One uppercase letter</li>
|
|
279
|
+
<li>One lowercase letter</li>
|
|
280
|
+
<li>One number</li>
|
|
281
|
+
<li>Not a common password</li>
|
|
282
|
+
</ul>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
</template>
|
|
286
|
+
|
|
287
|
+
<style module>
|
|
288
|
+
.custom-requirements {
|
|
289
|
+
max-width: 500px;
|
|
290
|
+
padding: 1.5rem;
|
|
291
|
+
border: 1px solid #e0e0e0;
|
|
292
|
+
border-radius: 0.5rem;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.form-group {
|
|
296
|
+
margin-bottom: 1.5rem;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.form-group label {
|
|
300
|
+
display: block;
|
|
301
|
+
margin-bottom: 0.5rem;
|
|
302
|
+
font-weight: 500;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.requirements-info {
|
|
306
|
+
padding: 1rem;
|
|
307
|
+
background-color: #f8f9fa;
|
|
308
|
+
border-radius: 0.25rem;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.requirements-info h4 {
|
|
312
|
+
margin: 0 0 0.5rem 0;
|
|
313
|
+
color: #333;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.requirements-info ul {
|
|
317
|
+
margin: 0;
|
|
318
|
+
padding-left: 1.5rem;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.requirements-info li {
|
|
322
|
+
margin-bottom: 0.25rem;
|
|
323
|
+
color: #666;
|
|
324
|
+
}
|
|
325
|
+
</style>
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Registration Form Integration
|
|
329
|
+
|
|
330
|
+
```vue
|
|
331
|
+
<script setup lang="ts">
|
|
332
|
+
import { ref, computed } from "vue";
|
|
333
|
+
import { InputSecure } from "@umbra-ui/core";
|
|
334
|
+
|
|
335
|
+
interface RegistrationForm {
|
|
336
|
+
username: string;
|
|
337
|
+
email: string;
|
|
338
|
+
password: string;
|
|
339
|
+
confirmPassword: string;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const form = ref<RegistrationForm>({
|
|
343
|
+
username: "",
|
|
344
|
+
email: "",
|
|
345
|
+
password: "",
|
|
346
|
+
confirmPassword: "",
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
const passwordValid = ref(false);
|
|
350
|
+
const passwordsMatch = ref(false);
|
|
351
|
+
|
|
352
|
+
const isFormValid = computed(() => {
|
|
353
|
+
return (
|
|
354
|
+
form.value.username &&
|
|
355
|
+
form.value.email &&
|
|
356
|
+
form.value.password &&
|
|
357
|
+
passwordValid.value &&
|
|
358
|
+
passwordsMatch.value
|
|
359
|
+
);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
const handlePasswordValid = (valid: boolean) => {
|
|
363
|
+
passwordValid.value = valid;
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
const handlePasswordChange = (password: string) => {
|
|
367
|
+
form.value.password = password;
|
|
368
|
+
passwordsMatch.value = password === form.value.confirmPassword;
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
const handleConfirmPasswordChange = (confirmPassword: string) => {
|
|
372
|
+
form.value.confirmPassword = confirmPassword;
|
|
373
|
+
passwordsMatch.value = form.value.password === confirmPassword;
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
const handleSubmit = () => {
|
|
377
|
+
if (isFormValid.value) {
|
|
378
|
+
console.log("Registration submitted:", form.value);
|
|
379
|
+
// Handle form submission
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
</script>
|
|
383
|
+
|
|
384
|
+
<template>
|
|
385
|
+
<div class="registration-form">
|
|
386
|
+
<h3>Create Account</h3>
|
|
387
|
+
|
|
388
|
+
<form @submit.prevent="handleSubmit">
|
|
389
|
+
<div class="form-group">
|
|
390
|
+
<label>Username *</label>
|
|
391
|
+
<input
|
|
392
|
+
v-model="form.username"
|
|
393
|
+
type="text"
|
|
394
|
+
placeholder="Choose a username"
|
|
395
|
+
required
|
|
396
|
+
/>
|
|
397
|
+
</div>
|
|
398
|
+
|
|
399
|
+
<div class="form-group">
|
|
400
|
+
<label>Email *</label>
|
|
401
|
+
<input
|
|
402
|
+
v-model="form.email"
|
|
403
|
+
type="email"
|
|
404
|
+
placeholder="your@email.com"
|
|
405
|
+
required
|
|
406
|
+
/>
|
|
407
|
+
</div>
|
|
408
|
+
|
|
409
|
+
<div class="form-group">
|
|
410
|
+
<label>Password *</label>
|
|
411
|
+
<InputSecure
|
|
412
|
+
v-model:value="form.password"
|
|
413
|
+
@update:value="handlePasswordChange"
|
|
414
|
+
@update:valid="handlePasswordValid"
|
|
415
|
+
placeholder="Create a password"
|
|
416
|
+
:show-strength="true"
|
|
417
|
+
:allow-generate="true"
|
|
418
|
+
:show-requirements="true"
|
|
419
|
+
/>
|
|
420
|
+
</div>
|
|
421
|
+
|
|
422
|
+
<div class="form-group">
|
|
423
|
+
<label>Confirm Password *</label>
|
|
424
|
+
<InputSecure
|
|
425
|
+
v-model:value="form.confirmPassword"
|
|
426
|
+
@update:value="handleConfirmPasswordChange"
|
|
427
|
+
placeholder="Confirm your password"
|
|
428
|
+
:show-strength="false"
|
|
429
|
+
:allow-generate="false"
|
|
430
|
+
:show-requirements="false"
|
|
431
|
+
/>
|
|
432
|
+
<div
|
|
433
|
+
v-if="form.confirmPassword && !passwordsMatch"
|
|
434
|
+
class="error-message"
|
|
435
|
+
>
|
|
436
|
+
Passwords do not match
|
|
437
|
+
</div>
|
|
438
|
+
</div>
|
|
439
|
+
|
|
440
|
+
<button type="submit" :disabled="!isFormValid" class="submit-button">
|
|
441
|
+
Create Account
|
|
442
|
+
</button>
|
|
443
|
+
</form>
|
|
444
|
+
</div>
|
|
445
|
+
</template>
|
|
446
|
+
|
|
447
|
+
<style module>
|
|
448
|
+
.registration-form {
|
|
449
|
+
max-width: 500px;
|
|
450
|
+
padding: 2rem;
|
|
451
|
+
border: 1px solid #e0e0e0;
|
|
452
|
+
border-radius: 0.5rem;
|
|
453
|
+
background-color: #fff;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.form-group {
|
|
457
|
+
margin-bottom: 1.5rem;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.form-group label {
|
|
461
|
+
display: block;
|
|
462
|
+
margin-bottom: 0.5rem;
|
|
463
|
+
font-weight: 500;
|
|
464
|
+
color: #333;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.form-group input {
|
|
468
|
+
width: 100%;
|
|
469
|
+
padding: 0.75rem;
|
|
470
|
+
border: 1px solid #ddd;
|
|
471
|
+
border-radius: 0.25rem;
|
|
472
|
+
font-size: 1rem;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.form-group input:focus {
|
|
476
|
+
outline: none;
|
|
477
|
+
border-color: #007bff;
|
|
478
|
+
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.error-message {
|
|
482
|
+
color: #dc3545;
|
|
483
|
+
font-size: 0.875rem;
|
|
484
|
+
margin-top: 0.25rem;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.submit-button {
|
|
488
|
+
width: 100%;
|
|
489
|
+
padding: 0.75rem;
|
|
490
|
+
background-color: #007bff;
|
|
491
|
+
color: white;
|
|
492
|
+
border: none;
|
|
493
|
+
border-radius: 0.25rem;
|
|
494
|
+
font-size: 1rem;
|
|
495
|
+
cursor: pointer;
|
|
496
|
+
transition: background-color 0.2s;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.submit-button:hover:not(:disabled) {
|
|
500
|
+
background-color: #0056b3;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.submit-button:disabled {
|
|
504
|
+
background-color: #6c757d;
|
|
505
|
+
cursor: not-allowed;
|
|
506
|
+
}
|
|
507
|
+
</style>
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Different States
|
|
511
|
+
|
|
512
|
+
```vue
|
|
513
|
+
<script setup lang="ts">
|
|
514
|
+
import { ref } from "vue";
|
|
515
|
+
import { InputSecure } from "@umbra-ui/core";
|
|
516
|
+
|
|
517
|
+
const normalPassword = ref("");
|
|
518
|
+
const disabledPassword = ref("password123");
|
|
519
|
+
const readonlyPassword = ref("readonly123");
|
|
520
|
+
const errorPassword = ref("weak");
|
|
521
|
+
</script>
|
|
522
|
+
|
|
523
|
+
<template>
|
|
524
|
+
<div class="states-example">
|
|
525
|
+
<h3>Input States</h3>
|
|
526
|
+
|
|
527
|
+
<div class="state-group">
|
|
528
|
+
<label>Normal State</label>
|
|
529
|
+
<InputSecure
|
|
530
|
+
v-model:value="normalPassword"
|
|
531
|
+
placeholder="Enter password"
|
|
532
|
+
state="normal"
|
|
533
|
+
:show-strength="true"
|
|
534
|
+
:show-requirements="true"
|
|
535
|
+
/>
|
|
536
|
+
</div>
|
|
537
|
+
|
|
538
|
+
<div class="state-group">
|
|
539
|
+
<label>Disabled State</label>
|
|
540
|
+
<InputSecure
|
|
541
|
+
v-model:value="disabledPassword"
|
|
542
|
+
state="disabled"
|
|
543
|
+
:show-strength="false"
|
|
544
|
+
:show-requirements="false"
|
|
545
|
+
/>
|
|
546
|
+
</div>
|
|
547
|
+
|
|
548
|
+
<div class="state-group">
|
|
549
|
+
<label>Readonly State</label>
|
|
550
|
+
<InputSecure
|
|
551
|
+
v-model:value="readonlyPassword"
|
|
552
|
+
state="readonly"
|
|
553
|
+
:show-strength="false"
|
|
554
|
+
:show-requirements="false"
|
|
555
|
+
/>
|
|
556
|
+
</div>
|
|
557
|
+
|
|
558
|
+
<div class="state-group">
|
|
559
|
+
<label>Error State (Weak Password)</label>
|
|
560
|
+
<InputSecure
|
|
561
|
+
v-model:value="errorPassword"
|
|
562
|
+
placeholder="Enter strong password"
|
|
563
|
+
state="normal"
|
|
564
|
+
:show-strength="true"
|
|
565
|
+
:show-requirements="true"
|
|
566
|
+
/>
|
|
567
|
+
</div>
|
|
568
|
+
</div>
|
|
569
|
+
</template>
|
|
570
|
+
|
|
571
|
+
<style module>
|
|
572
|
+
.states-example {
|
|
573
|
+
max-width: 500px;
|
|
574
|
+
padding: 1.5rem;
|
|
575
|
+
border: 1px solid #e0e0e0;
|
|
576
|
+
border-radius: 0.5rem;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.state-group {
|
|
580
|
+
margin-bottom: 1.5rem;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
.state-group label {
|
|
584
|
+
display: block;
|
|
585
|
+
margin-bottom: 0.5rem;
|
|
586
|
+
font-weight: 500;
|
|
587
|
+
color: #333;
|
|
588
|
+
}
|
|
589
|
+
</style>
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
### Password Manager Integration
|
|
593
|
+
|
|
594
|
+
```vue
|
|
595
|
+
<script setup lang="ts">
|
|
596
|
+
import { ref, computed } from "vue";
|
|
597
|
+
import { InputSecure } from "@umbra-ui/core";
|
|
598
|
+
|
|
599
|
+
const masterPassword = ref("");
|
|
600
|
+
const generatedPasswords = ref<string[]>([]);
|
|
601
|
+
|
|
602
|
+
const handleMasterPasswordValid = (valid: boolean) => {
|
|
603
|
+
console.log("Master password valid:", valid);
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
const generateNewPassword = () => {
|
|
607
|
+
// This would typically call a password generation service
|
|
608
|
+
const newPassword = "Generated" + Math.random().toString(36).substr(2, 9);
|
|
609
|
+
generatedPasswords.value.push(newPassword);
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
const copyPassword = async (password: string) => {
|
|
613
|
+
try {
|
|
614
|
+
await navigator.clipboard.writeText(password);
|
|
615
|
+
console.log("Password copied to clipboard");
|
|
616
|
+
} catch (err) {
|
|
617
|
+
console.error("Failed to copy password");
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
</script>
|
|
621
|
+
|
|
622
|
+
<template>
|
|
623
|
+
<div class="password-manager">
|
|
624
|
+
<h3>Password Manager</h3>
|
|
625
|
+
|
|
626
|
+
<div class="master-password-section">
|
|
627
|
+
<h4>Master Password</h4>
|
|
628
|
+
<InputSecure
|
|
629
|
+
v-model:value="masterPassword"
|
|
630
|
+
@update:valid="handleMasterPasswordValid"
|
|
631
|
+
placeholder="Enter master password"
|
|
632
|
+
:show-strength="true"
|
|
633
|
+
:allow-generate="false"
|
|
634
|
+
:show-requirements="true"
|
|
635
|
+
:min-length="12"
|
|
636
|
+
/>
|
|
637
|
+
</div>
|
|
638
|
+
|
|
639
|
+
<div class="generated-passwords-section">
|
|
640
|
+
<div class="section-header">
|
|
641
|
+
<h4>Generated Passwords</h4>
|
|
642
|
+
<button @click="generateNewPassword" class="generate-btn">
|
|
643
|
+
Generate New
|
|
644
|
+
</button>
|
|
645
|
+
</div>
|
|
646
|
+
|
|
647
|
+
<div v-if="generatedPasswords.length === 0" class="empty-state">
|
|
648
|
+
<p>No passwords generated yet</p>
|
|
649
|
+
</div>
|
|
650
|
+
|
|
651
|
+
<div v-else class="password-list">
|
|
652
|
+
<div
|
|
653
|
+
v-for="(password, index) in generatedPasswords"
|
|
654
|
+
:key="index"
|
|
655
|
+
class="password-item"
|
|
656
|
+
>
|
|
657
|
+
<InputSecure
|
|
658
|
+
v-model:value="generatedPasswords[index]"
|
|
659
|
+
:show-strength="false"
|
|
660
|
+
:allow-generate="false"
|
|
661
|
+
:show-requirements="false"
|
|
662
|
+
state="readonly"
|
|
663
|
+
/>
|
|
664
|
+
<button
|
|
665
|
+
@click="copyPassword(password)"
|
|
666
|
+
class="copy-btn"
|
|
667
|
+
title="Copy password"
|
|
668
|
+
>
|
|
669
|
+
Copy
|
|
670
|
+
</button>
|
|
671
|
+
</div>
|
|
672
|
+
</div>
|
|
673
|
+
</div>
|
|
674
|
+
</div>
|
|
675
|
+
</template>
|
|
676
|
+
|
|
677
|
+
<style module>
|
|
678
|
+
.password-manager {
|
|
679
|
+
max-width: 600px;
|
|
680
|
+
padding: 1.5rem;
|
|
681
|
+
border: 1px solid #e0e0e0;
|
|
682
|
+
border-radius: 0.5rem;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.master-password-section {
|
|
686
|
+
margin-bottom: 2rem;
|
|
687
|
+
padding: 1rem;
|
|
688
|
+
border: 1px solid #f0f0f0;
|
|
689
|
+
border-radius: 0.25rem;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
.master-password-section h4 {
|
|
693
|
+
margin: 0 0 1rem 0;
|
|
694
|
+
color: #333;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
.generated-passwords-section h4 {
|
|
698
|
+
margin: 0 0 1rem 0;
|
|
699
|
+
color: #333;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
.section-header {
|
|
703
|
+
display: flex;
|
|
704
|
+
justify-content: space-between;
|
|
705
|
+
align-items: center;
|
|
706
|
+
margin-bottom: 1rem;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
.generate-btn {
|
|
710
|
+
padding: 0.5rem 1rem;
|
|
711
|
+
background-color: #28a745;
|
|
712
|
+
color: white;
|
|
713
|
+
border: none;
|
|
714
|
+
border-radius: 0.25rem;
|
|
715
|
+
cursor: pointer;
|
|
716
|
+
font-size: 0.875rem;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
.generate-btn:hover {
|
|
720
|
+
background-color: #218838;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
.empty-state {
|
|
724
|
+
text-align: center;
|
|
725
|
+
padding: 2rem;
|
|
726
|
+
color: #666;
|
|
727
|
+
font-style: italic;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.password-list {
|
|
731
|
+
display: flex;
|
|
732
|
+
flex-direction: column;
|
|
733
|
+
gap: 0.75rem;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.password-item {
|
|
737
|
+
display: flex;
|
|
738
|
+
align-items: center;
|
|
739
|
+
gap: 0.75rem;
|
|
740
|
+
padding: 0.75rem;
|
|
741
|
+
border: 1px solid #f0f0f0;
|
|
742
|
+
border-radius: 0.25rem;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
.copy-btn {
|
|
746
|
+
padding: 0.5rem 0.75rem;
|
|
747
|
+
background-color: #007bff;
|
|
748
|
+
color: white;
|
|
749
|
+
border: none;
|
|
750
|
+
border-radius: 0.25rem;
|
|
751
|
+
cursor: pointer;
|
|
752
|
+
font-size: 0.875rem;
|
|
753
|
+
flex-shrink: 0;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
.copy-btn:hover {
|
|
757
|
+
background-color: #0056b3;
|
|
758
|
+
}
|
|
759
|
+
</style>
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
## Technical Notes
|
|
763
|
+
|
|
764
|
+
- Password strength calculation considers length, character variety, and pattern detection
|
|
765
|
+
- Common password prevention uses a curated list of weak passwords
|
|
766
|
+
- Password generation creates cryptographically secure passwords meeting all requirements
|
|
767
|
+
- Copy functionality uses the modern Clipboard API with fallback handling
|
|
768
|
+
- Input states provide proper accessibility and visual feedback
|
|
769
|
+
- Responsive design prevents zoom on mobile devices with proper font sizing
|
|
770
|
+
- Requirements list shows/hides based on focus state and validation status
|
|
771
|
+
- Strength indicator updates in real-time with smooth color transitions
|