@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,1439 @@
|
|
|
1
|
+
# ColorPicker
|
|
2
|
+
|
|
3
|
+
A comprehensive color picker component built with Vue 3 Composition API and TypeScript. The ColorPicker provides an intuitive interface for selecting colors from a curated palette with support for customizable dot styling, smart positioning using Floating UI, and comprehensive color information display.
|
|
4
|
+
|
|
5
|
+
## Installation/Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { ColorPicker } from "@umbra-ui/core";
|
|
9
|
+
import type { Color, ColorGroup } from "@umbra-ui/core";
|
|
10
|
+
import { colors, colorPickerColors, colorGroups } from "@umbra-ui/core";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Dependencies:**
|
|
14
|
+
|
|
15
|
+
- Vue 3.x
|
|
16
|
+
- @floating-ui/vue (for positioning)
|
|
17
|
+
|
|
18
|
+
## Basic Usage
|
|
19
|
+
|
|
20
|
+
```vue
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
import { ref } from "vue";
|
|
23
|
+
import { ColorPicker, colorPickerColors } from "@umbra-ui/core";
|
|
24
|
+
import type { Color } from "@umbra-ui/core";
|
|
25
|
+
|
|
26
|
+
const selectedColor = ref<Color>(colorPickerColors.gray700);
|
|
27
|
+
|
|
28
|
+
const handleColorChange = (color: Color) => {
|
|
29
|
+
console.log("Selected color:", color);
|
|
30
|
+
console.log("Color name:", color.name);
|
|
31
|
+
console.log("Color weight:", color.weight);
|
|
32
|
+
console.log("Color hex:", color.hex);
|
|
33
|
+
};
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<div class="app">
|
|
38
|
+
<h2>Choose a Color</h2>
|
|
39
|
+
|
|
40
|
+
<ColorPicker
|
|
41
|
+
v-model:color="selectedColor"
|
|
42
|
+
@update:color="handleColorChange"
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
<div v-if="selectedColor" class="color-info">
|
|
46
|
+
<div
|
|
47
|
+
class="color-preview"
|
|
48
|
+
:style="{ backgroundColor: selectedColor.hex }"
|
|
49
|
+
/>
|
|
50
|
+
<div class="color-details">
|
|
51
|
+
<h3>{{ selectedColor.name }}({{ selectedColor.weight }})</h3>
|
|
52
|
+
<p>{{ selectedColor.hex }}</p>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<style module>
|
|
59
|
+
.app {
|
|
60
|
+
padding: 24px;
|
|
61
|
+
max-width: 400px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.color-info {
|
|
65
|
+
margin-top: 20px;
|
|
66
|
+
display: flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
gap: 16px;
|
|
69
|
+
padding: 16px;
|
|
70
|
+
background: #f8f9fa;
|
|
71
|
+
border-radius: 8px;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.color-preview {
|
|
75
|
+
width: 40px;
|
|
76
|
+
height: 40px;
|
|
77
|
+
border-radius: 50%;
|
|
78
|
+
border: 2px solid #e9ecef;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.color-details h3 {
|
|
82
|
+
margin: 0 0 4px 0;
|
|
83
|
+
font-size: 16px;
|
|
84
|
+
font-weight: 600;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.color-details p {
|
|
88
|
+
margin: 0;
|
|
89
|
+
color: #6c757d;
|
|
90
|
+
font-family: monospace;
|
|
91
|
+
}
|
|
92
|
+
</style>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Props
|
|
96
|
+
|
|
97
|
+
| Prop Name | Type | Required | Default | Description |
|
|
98
|
+
| ---------------------- | ------------------ | -------- | ---------------------------------------------- | ----------------------------------------------- |
|
|
99
|
+
| `color` | `Color` | Yes | `colorPickerColors.gray700` | Currently selected color |
|
|
100
|
+
| `pickerOffsetX` | `number` | No | `0` | Horizontal offset for picker positioning |
|
|
101
|
+
| `preventPopup` | `boolean` | No | `false` | Whether to prevent the popup from opening |
|
|
102
|
+
| `dotSize` | `number \| string` | No | `"1.25rem"` | Size of the color dot |
|
|
103
|
+
| `dotRadius` | `number \| string` | No | `"999px"` | Border radius of the color dot |
|
|
104
|
+
| `dotBorderWidth` | `number` | No | `1` | Border width of the color dot |
|
|
105
|
+
| `dotBorderColor` | `string` | No | `"var(--colorpicker-dot-border-color)"` | Border color of the color dot |
|
|
106
|
+
| `dotBorderColorActive` | `string` | No | `"var(--colorpicker-dot-border-color-active)"` | Border color when picker is open |
|
|
107
|
+
| `showColorInfo` | `boolean` | No | `true` | Whether to show color information in the picker |
|
|
108
|
+
|
|
109
|
+
## Color Interface
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
interface Color {
|
|
113
|
+
name: string | null;
|
|
114
|
+
hex: string;
|
|
115
|
+
weight: number | null;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Color Properties
|
|
120
|
+
|
|
121
|
+
| Property | Type | Description |
|
|
122
|
+
| -------- | ---------------- | ----------------------------------------- |
|
|
123
|
+
| `name` | `string \| null` | Color name (e.g., "Gray", "Blue") |
|
|
124
|
+
| `hex` | `string` | Hexadecimal color value (e.g., "#374151") |
|
|
125
|
+
| `weight` | `number \| null` | Color weight/shade (e.g., 200, 500, 700) |
|
|
126
|
+
|
|
127
|
+
## Events
|
|
128
|
+
|
|
129
|
+
| Event Name | Payload Type | Description |
|
|
130
|
+
| -------------- | ------------ | -------------------------------- |
|
|
131
|
+
| `update:color` | `Color` | Emitted when a color is selected |
|
|
132
|
+
|
|
133
|
+
## Available Colors
|
|
134
|
+
|
|
135
|
+
The ColorPicker includes a comprehensive palette of 200 colors across 25 color groups:
|
|
136
|
+
|
|
137
|
+
### Color Groups
|
|
138
|
+
|
|
139
|
+
- **Neutrals**: Gray, Zinc, Neutral, Stone
|
|
140
|
+
- **Warm Colors**: Red, Orange, Amber, Yellow
|
|
141
|
+
- **Cool Colors**: Lime, Green, Emerald, Teal, Cyan, Sky, Blue, Indigo
|
|
142
|
+
- **Purple Tones**: Violet, Purple, Fuchsia
|
|
143
|
+
- **Pink Tones**: Pink, Rose
|
|
144
|
+
|
|
145
|
+
### Color Weights
|
|
146
|
+
|
|
147
|
+
Each color group includes 8 weight variations:
|
|
148
|
+
|
|
149
|
+
- **200**: Lightest shade
|
|
150
|
+
- **300**: Light shade
|
|
151
|
+
- **400**: Medium-light shade
|
|
152
|
+
- **500**: Medium shade (base color)
|
|
153
|
+
- **600**: Medium-dark shade
|
|
154
|
+
- **700**: Dark shade
|
|
155
|
+
- **800**: Darker shade
|
|
156
|
+
- **900**: Darkest shade
|
|
157
|
+
|
|
158
|
+
### Accessing Colors
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { colorPickerColors, colors, colorGroups } from "@umbra-ui/core";
|
|
162
|
+
|
|
163
|
+
// Access by name and weight
|
|
164
|
+
const blue500 = colorPickerColors.blue500; // { name: "Blue", hex: "#3B82F6", weight: 500 }
|
|
165
|
+
|
|
166
|
+
// Access all colors
|
|
167
|
+
const allColors = colors; // Array of all 200 colors
|
|
168
|
+
|
|
169
|
+
// Access color groups
|
|
170
|
+
const blueGroup = colorGroups.find((group) => group.name === "Blue");
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## CSS Customization
|
|
174
|
+
|
|
175
|
+
### Layout Variables
|
|
176
|
+
|
|
177
|
+
```css
|
|
178
|
+
.color-picker {
|
|
179
|
+
--picker-button-bg: #ffffff;
|
|
180
|
+
--picker-button-border: 1px solid #e9ecef;
|
|
181
|
+
--picker-button-hover-bg: #f8f9fa;
|
|
182
|
+
--picker-button-hover-border: 1px solid #dee2e6;
|
|
183
|
+
--picker-button-hover-shadow: rgba(0, 0, 0, 0.1);
|
|
184
|
+
--picker-button-hover-inset-shadow: rgba(255, 255, 255, 0.1);
|
|
185
|
+
--picker-button-selected-bg: #e3f2fd;
|
|
186
|
+
--picker-button-selected-shadow: rgba(0, 0, 0, 0.1);
|
|
187
|
+
--picker-button-selected-inset-shadow: rgba(255, 255, 255, 0.1);
|
|
188
|
+
--picker-picker-bg: #ffffff;
|
|
189
|
+
--picker-picker-border: 1px solid #e9ecef;
|
|
190
|
+
--picker-picker-shadow: rgba(0, 0, 0, 0.1);
|
|
191
|
+
--picker-picker-inset-shadow: rgba(255, 255, 255, 0.1);
|
|
192
|
+
--picker-selection-bar-bg: #f8f9fa;
|
|
193
|
+
--picker-selection-bar-text: #212529;
|
|
194
|
+
--picker-selection-bar-border: #e9ecef;
|
|
195
|
+
--picker-border-light: #e9ecef;
|
|
196
|
+
--picker-overlay-bg: rgba(0, 0, 0, 0.1);
|
|
197
|
+
--colorpicker-picker-shadow: none;
|
|
198
|
+
--colorpicker-color-cell-border: #838383;
|
|
199
|
+
--colorpicker-color-cell-selected-border: #ffffff;
|
|
200
|
+
--colorpicker-color-dot-bg: #ffffff;
|
|
201
|
+
--colorpicker-dot-border-color: #9ca3af;
|
|
202
|
+
--colorpicker-dot-border-color-active: #374151;
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Container Styling
|
|
207
|
+
|
|
208
|
+
```css
|
|
209
|
+
.color-picker {
|
|
210
|
+
display: flex;
|
|
211
|
+
align-items: center;
|
|
212
|
+
justify-content: center;
|
|
213
|
+
max-width: fit-content;
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Button Styling
|
|
218
|
+
|
|
219
|
+
```css
|
|
220
|
+
.color-picker .button {
|
|
221
|
+
border-radius: 0.353rem;
|
|
222
|
+
padding: 0.588rem;
|
|
223
|
+
display: flex;
|
|
224
|
+
align-items: center;
|
|
225
|
+
justify-content: center;
|
|
226
|
+
cursor: pointer;
|
|
227
|
+
background-color: var(--picker-button-bg);
|
|
228
|
+
border: var(--picker-button-border);
|
|
229
|
+
transition: all 0.3s ease;
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Picker Styling
|
|
234
|
+
|
|
235
|
+
```css
|
|
236
|
+
.color-picker .picker {
|
|
237
|
+
position: absolute;
|
|
238
|
+
background-color: var(--picker-picker-bg);
|
|
239
|
+
border-radius: 0.353rem;
|
|
240
|
+
z-index: 1000;
|
|
241
|
+
overflow: auto;
|
|
242
|
+
box-shadow: var(--colorpicker-picker-shadow);
|
|
243
|
+
border: var(--picker-picker-border);
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Color Grid Styling
|
|
248
|
+
|
|
249
|
+
```css
|
|
250
|
+
.color-picker .color_list {
|
|
251
|
+
display: grid;
|
|
252
|
+
grid-template-columns: repeat(8, 1fr);
|
|
253
|
+
gap: 0.706rem;
|
|
254
|
+
padding: 0.706rem;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.color-picker .color_cell {
|
|
258
|
+
width: 1.412rem;
|
|
259
|
+
height: 1.412rem;
|
|
260
|
+
border: 1px solid var(--colorpicker-color-cell-border);
|
|
261
|
+
border-radius: 999px;
|
|
262
|
+
display: flex;
|
|
263
|
+
align-items: center;
|
|
264
|
+
justify-content: center;
|
|
265
|
+
transition: transform 0.3s ease, scale 0.3s ease;
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Examples
|
|
270
|
+
|
|
271
|
+
### Theme Color Selector
|
|
272
|
+
|
|
273
|
+
```vue
|
|
274
|
+
<script setup lang="ts">
|
|
275
|
+
import { ref } from "vue";
|
|
276
|
+
import { ColorPicker, colorPickerColors } from "@umbra-ui/core";
|
|
277
|
+
import type { Color } from "@umbra-ui/core";
|
|
278
|
+
|
|
279
|
+
const themeColors = [
|
|
280
|
+
colorPickerColors.blue500,
|
|
281
|
+
colorPickerColors.green500,
|
|
282
|
+
colorPickerColors.purple500,
|
|
283
|
+
colorPickerColors.orange500,
|
|
284
|
+
colorPickerColors.red500,
|
|
285
|
+
colorPickerColors.teal500,
|
|
286
|
+
];
|
|
287
|
+
|
|
288
|
+
const selectedThemeColor = ref<Color>(colorPickerColors.blue500);
|
|
289
|
+
|
|
290
|
+
const handleThemeColorChange = (color: Color) => {
|
|
291
|
+
console.log("Theme color changed to:", color);
|
|
292
|
+
// Apply theme color to your application
|
|
293
|
+
document.documentElement.style.setProperty("--primary-color", color.hex);
|
|
294
|
+
};
|
|
295
|
+
</script>
|
|
296
|
+
|
|
297
|
+
<template>
|
|
298
|
+
<div class="theme-selector">
|
|
299
|
+
<div class="selector-header">
|
|
300
|
+
<h3>Theme Colors</h3>
|
|
301
|
+
<p>Choose your application's primary color</p>
|
|
302
|
+
</div>
|
|
303
|
+
|
|
304
|
+
<ColorPicker
|
|
305
|
+
v-model:color="selectedThemeColor"
|
|
306
|
+
:dot-size="32"
|
|
307
|
+
:dot-radius="8"
|
|
308
|
+
:dot-border-width="2"
|
|
309
|
+
@update:color="handleThemeColorChange"
|
|
310
|
+
/>
|
|
311
|
+
|
|
312
|
+
<div class="theme-preview">
|
|
313
|
+
<div
|
|
314
|
+
class="preview-header"
|
|
315
|
+
:style="{ backgroundColor: selectedThemeColor.hex }"
|
|
316
|
+
>
|
|
317
|
+
<h4>Preview</h4>
|
|
318
|
+
</div>
|
|
319
|
+
<div class="preview-content">
|
|
320
|
+
<p>
|
|
321
|
+
This is how your theme will look with {{ selectedThemeColor.name }}({{
|
|
322
|
+
selectedThemeColor.weight
|
|
323
|
+
}})
|
|
324
|
+
</p>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
</template>
|
|
329
|
+
|
|
330
|
+
<style module>
|
|
331
|
+
.theme-selector {
|
|
332
|
+
padding: 24px;
|
|
333
|
+
max-width: 500px;
|
|
334
|
+
background: #ffffff;
|
|
335
|
+
border-radius: 12px;
|
|
336
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.selector-header {
|
|
340
|
+
margin-bottom: 24px;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.selector-header h3 {
|
|
344
|
+
font-size: 20px;
|
|
345
|
+
font-weight: 600;
|
|
346
|
+
color: #1a202c;
|
|
347
|
+
margin: 0 0 8px 0;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.selector-header p {
|
|
351
|
+
color: #718096;
|
|
352
|
+
margin: 0;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.theme-preview {
|
|
356
|
+
margin-top: 24px;
|
|
357
|
+
border-radius: 8px;
|
|
358
|
+
overflow: hidden;
|
|
359
|
+
border: 1px solid #e2e8f0;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.preview-header {
|
|
363
|
+
padding: 16px;
|
|
364
|
+
color: white;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.preview-header h4 {
|
|
368
|
+
margin: 0;
|
|
369
|
+
font-size: 16px;
|
|
370
|
+
font-weight: 600;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.preview-content {
|
|
374
|
+
padding: 16px;
|
|
375
|
+
background: #f7fafc;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.preview-content p {
|
|
379
|
+
margin: 0;
|
|
380
|
+
color: #4a5568;
|
|
381
|
+
}
|
|
382
|
+
</style>
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Custom Dot Styling
|
|
386
|
+
|
|
387
|
+
```vue
|
|
388
|
+
<script setup lang="ts">
|
|
389
|
+
import { ref } from "vue";
|
|
390
|
+
import { ColorPicker, colorPickerColors } from "@umbra-ui/core";
|
|
391
|
+
import type { Color } from "@umbra-ui/core";
|
|
392
|
+
|
|
393
|
+
const selectedColor = ref<Color>(colorPickerColors.emerald500);
|
|
394
|
+
|
|
395
|
+
const handleColorChange = (color: Color) => {
|
|
396
|
+
console.log("Selected color:", color);
|
|
397
|
+
};
|
|
398
|
+
</script>
|
|
399
|
+
|
|
400
|
+
<template>
|
|
401
|
+
<div class="custom-styling">
|
|
402
|
+
<h3>Custom Dot Styling</h3>
|
|
403
|
+
|
|
404
|
+
<div class="picker-row">
|
|
405
|
+
<div class="picker-item">
|
|
406
|
+
<h4>Square Dot</h4>
|
|
407
|
+
<ColorPicker
|
|
408
|
+
v-model:color="selectedColor"
|
|
409
|
+
:dot-size="24"
|
|
410
|
+
:dot-radius="4"
|
|
411
|
+
:dot-border-width="2"
|
|
412
|
+
dot-border-color="#e2e8f0"
|
|
413
|
+
dot-border-color-active="#4299e1"
|
|
414
|
+
@update:color="handleColorChange"
|
|
415
|
+
/>
|
|
416
|
+
</div>
|
|
417
|
+
|
|
418
|
+
<div class="picker-item">
|
|
419
|
+
<h4>Large Round Dot</h4>
|
|
420
|
+
<ColorPicker
|
|
421
|
+
v-model:color="selectedColor"
|
|
422
|
+
:dot-size="40"
|
|
423
|
+
:dot-radius="999"
|
|
424
|
+
:dot-border-width="3"
|
|
425
|
+
dot-border-color="#cbd5e0"
|
|
426
|
+
dot-border-color-active="#2b6cb0"
|
|
427
|
+
@update:color="handleColorChange"
|
|
428
|
+
/>
|
|
429
|
+
</div>
|
|
430
|
+
|
|
431
|
+
<div class="picker-item">
|
|
432
|
+
<h4>Small Dot</h4>
|
|
433
|
+
<ColorPicker
|
|
434
|
+
v-model:color="selectedColor"
|
|
435
|
+
:dot-size="16"
|
|
436
|
+
:dot-radius="999"
|
|
437
|
+
:dot-border-width="1"
|
|
438
|
+
dot-border-color="#a0aec0"
|
|
439
|
+
dot-border-color-active="#1a365d"
|
|
440
|
+
@update:color="handleColorChange"
|
|
441
|
+
/>
|
|
442
|
+
</div>
|
|
443
|
+
</div>
|
|
444
|
+
</div>
|
|
445
|
+
</template>
|
|
446
|
+
|
|
447
|
+
<style module>
|
|
448
|
+
.custom-styling {
|
|
449
|
+
padding: 24px;
|
|
450
|
+
max-width: 600px;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.picker-row {
|
|
454
|
+
display: flex;
|
|
455
|
+
gap: 32px;
|
|
456
|
+
margin-top: 20px;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.picker-item {
|
|
460
|
+
text-align: center;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.picker-item h4 {
|
|
464
|
+
font-size: 14px;
|
|
465
|
+
font-weight: 500;
|
|
466
|
+
color: #4a5568;
|
|
467
|
+
margin: 0 0 12px 0;
|
|
468
|
+
}
|
|
469
|
+
</style>
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Color Palette Builder
|
|
473
|
+
|
|
474
|
+
```vue
|
|
475
|
+
<script setup lang="ts">
|
|
476
|
+
import { ref } from "vue";
|
|
477
|
+
import { ColorPicker, colorPickerColors, colorGroups } from "@umbra-ui/core";
|
|
478
|
+
import type { Color, ColorGroup } from "@umbra-ui/core";
|
|
479
|
+
|
|
480
|
+
const selectedColors = ref<Color[]>([
|
|
481
|
+
colorPickerColors.blue500,
|
|
482
|
+
colorPickerColors.green500,
|
|
483
|
+
colorPickerColors.orange500,
|
|
484
|
+
]);
|
|
485
|
+
|
|
486
|
+
const addColor = (color: Color) => {
|
|
487
|
+
if (!selectedColors.value.find((c) => c.hex === color.hex)) {
|
|
488
|
+
selectedColors.value.push(color);
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
const removeColor = (colorToRemove: Color) => {
|
|
493
|
+
selectedColors.value = selectedColors.value.filter(
|
|
494
|
+
(color) => color.hex !== colorToRemove.hex
|
|
495
|
+
);
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
const clearPalette = () => {
|
|
499
|
+
selectedColors.value = [];
|
|
500
|
+
};
|
|
501
|
+
</script>
|
|
502
|
+
|
|
503
|
+
<template>
|
|
504
|
+
<div class="palette-builder">
|
|
505
|
+
<div class="builder-header">
|
|
506
|
+
<h3>Color Palette Builder</h3>
|
|
507
|
+
<p>Build your custom color palette</p>
|
|
508
|
+
</div>
|
|
509
|
+
|
|
510
|
+
<div class="color-picker-section">
|
|
511
|
+
<h4>Add Colors</h4>
|
|
512
|
+
<ColorPicker
|
|
513
|
+
:color="colorPickerColors.gray500"
|
|
514
|
+
@update:color="addColor"
|
|
515
|
+
/>
|
|
516
|
+
</div>
|
|
517
|
+
|
|
518
|
+
<div class="palette-section">
|
|
519
|
+
<div class="palette-header">
|
|
520
|
+
<h4>Your Palette ({{ selectedColors.length }} colors)</h4>
|
|
521
|
+
<button
|
|
522
|
+
@click="clearPalette"
|
|
523
|
+
class="clear-btn"
|
|
524
|
+
v-if="selectedColors.length > 0"
|
|
525
|
+
>
|
|
526
|
+
Clear All
|
|
527
|
+
</button>
|
|
528
|
+
</div>
|
|
529
|
+
|
|
530
|
+
<div v-if="selectedColors.length === 0" class="empty-palette">
|
|
531
|
+
<p>
|
|
532
|
+
No colors selected yet. Choose colors above to build your palette.
|
|
533
|
+
</p>
|
|
534
|
+
</div>
|
|
535
|
+
|
|
536
|
+
<div v-else class="palette-grid">
|
|
537
|
+
<div
|
|
538
|
+
v-for="color in selectedColors"
|
|
539
|
+
:key="color.hex"
|
|
540
|
+
class="palette-item"
|
|
541
|
+
>
|
|
542
|
+
<div class="palette-color" :style="{ backgroundColor: color.hex }" />
|
|
543
|
+
<div class="palette-info">
|
|
544
|
+
<p class="color-name">{{ color.name }}({{ color.weight }})</p>
|
|
545
|
+
<p class="color-hex">{{ color.hex }}</p>
|
|
546
|
+
</div>
|
|
547
|
+
<button @click="removeColor(color)" class="remove-btn">×</button>
|
|
548
|
+
</div>
|
|
549
|
+
</div>
|
|
550
|
+
</div>
|
|
551
|
+
</div>
|
|
552
|
+
</template>
|
|
553
|
+
|
|
554
|
+
<style module>
|
|
555
|
+
.palette-builder {
|
|
556
|
+
padding: 24px;
|
|
557
|
+
max-width: 600px;
|
|
558
|
+
background: #ffffff;
|
|
559
|
+
border-radius: 12px;
|
|
560
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
.builder-header {
|
|
564
|
+
margin-bottom: 32px;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.builder-header h3 {
|
|
568
|
+
font-size: 20px;
|
|
569
|
+
font-weight: 600;
|
|
570
|
+
color: #1a202c;
|
|
571
|
+
margin: 0 0 8px 0;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
.builder-header p {
|
|
575
|
+
color: #718096;
|
|
576
|
+
margin: 0;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.color-picker-section {
|
|
580
|
+
margin-bottom: 32px;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
.color-picker-section h4 {
|
|
584
|
+
font-size: 16px;
|
|
585
|
+
font-weight: 500;
|
|
586
|
+
color: #2d3748;
|
|
587
|
+
margin: 0 0 16px 0;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.palette-header {
|
|
591
|
+
display: flex;
|
|
592
|
+
align-items: center;
|
|
593
|
+
justify-content: space-between;
|
|
594
|
+
margin-bottom: 16px;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.palette-header h4 {
|
|
598
|
+
font-size: 16px;
|
|
599
|
+
font-weight: 500;
|
|
600
|
+
color: #2d3748;
|
|
601
|
+
margin: 0;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.clear-btn {
|
|
605
|
+
padding: 6px 12px;
|
|
606
|
+
background: #fed7d7;
|
|
607
|
+
color: #c53030;
|
|
608
|
+
border: none;
|
|
609
|
+
border-radius: 4px;
|
|
610
|
+
font-size: 12px;
|
|
611
|
+
font-weight: 500;
|
|
612
|
+
cursor: pointer;
|
|
613
|
+
transition: background 0.2s ease;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
.clear-btn:hover {
|
|
617
|
+
background: #feb2b2;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
.empty-palette {
|
|
621
|
+
padding: 32px;
|
|
622
|
+
text-align: center;
|
|
623
|
+
background: #f7fafc;
|
|
624
|
+
border-radius: 8px;
|
|
625
|
+
border: 2px dashed #cbd5e0;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.empty-palette p {
|
|
629
|
+
color: #718096;
|
|
630
|
+
margin: 0;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.palette-grid {
|
|
634
|
+
display: grid;
|
|
635
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
636
|
+
gap: 16px;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.palette-item {
|
|
640
|
+
display: flex;
|
|
641
|
+
align-items: center;
|
|
642
|
+
gap: 12px;
|
|
643
|
+
padding: 12px;
|
|
644
|
+
background: #f7fafc;
|
|
645
|
+
border-radius: 8px;
|
|
646
|
+
border: 1px solid #e2e8f0;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.palette-color {
|
|
650
|
+
width: 32px;
|
|
651
|
+
height: 32px;
|
|
652
|
+
border-radius: 50%;
|
|
653
|
+
border: 2px solid #e2e8f0;
|
|
654
|
+
flex-shrink: 0;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.palette-info {
|
|
658
|
+
flex: 1;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.color-name {
|
|
662
|
+
font-size: 14px;
|
|
663
|
+
font-weight: 500;
|
|
664
|
+
color: #2d3748;
|
|
665
|
+
margin: 0 0 2px 0;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.color-hex {
|
|
669
|
+
font-size: 12px;
|
|
670
|
+
color: #718096;
|
|
671
|
+
font-family: monospace;
|
|
672
|
+
margin: 0;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
.remove-btn {
|
|
676
|
+
width: 24px;
|
|
677
|
+
height: 24px;
|
|
678
|
+
background: #fed7d7;
|
|
679
|
+
color: #c53030;
|
|
680
|
+
border: none;
|
|
681
|
+
border-radius: 50%;
|
|
682
|
+
font-size: 16px;
|
|
683
|
+
font-weight: bold;
|
|
684
|
+
cursor: pointer;
|
|
685
|
+
display: flex;
|
|
686
|
+
align-items: center;
|
|
687
|
+
justify-content: center;
|
|
688
|
+
transition: background 0.2s ease;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
.remove-btn:hover {
|
|
692
|
+
background: #feb2b2;
|
|
693
|
+
}
|
|
694
|
+
</style>
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### Brand Color Selector
|
|
698
|
+
|
|
699
|
+
```vue
|
|
700
|
+
<script setup lang="ts">
|
|
701
|
+
import { ref } from "vue";
|
|
702
|
+
import { ColorPicker, colorPickerColors } from "@umbra-ui/core";
|
|
703
|
+
import type { Color } from "@umbra-ui/core";
|
|
704
|
+
|
|
705
|
+
interface BrandColors {
|
|
706
|
+
primary: Color;
|
|
707
|
+
secondary: Color;
|
|
708
|
+
accent: Color;
|
|
709
|
+
neutral: Color;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
const brandColors = ref<BrandColors>({
|
|
713
|
+
primary: colorPickerColors.blue600,
|
|
714
|
+
secondary: colorPickerColors.gray600,
|
|
715
|
+
accent: colorPickerColors.orange500,
|
|
716
|
+
neutral: colorPickerColors.gray300,
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
const updateBrandColor = (key: keyof BrandColors, color: Color) => {
|
|
720
|
+
brandColors.value[key] = color;
|
|
721
|
+
console.log(`Updated ${key} color:`, color);
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
const generateCSS = () => {
|
|
725
|
+
const css = `
|
|
726
|
+
:root {
|
|
727
|
+
--brand-primary: ${brandColors.value.primary.hex};
|
|
728
|
+
--brand-secondary: ${brandColors.value.secondary.hex};
|
|
729
|
+
--brand-accent: ${brandColors.value.accent.hex};
|
|
730
|
+
--brand-neutral: ${brandColors.value.neutral.hex};
|
|
731
|
+
}`;
|
|
732
|
+
console.log("Generated CSS:", css);
|
|
733
|
+
return css;
|
|
734
|
+
};
|
|
735
|
+
</script>
|
|
736
|
+
|
|
737
|
+
<template>
|
|
738
|
+
<div class="brand-selector">
|
|
739
|
+
<div class="selector-header">
|
|
740
|
+
<h3>Brand Color System</h3>
|
|
741
|
+
<p>Define your brand's color palette</p>
|
|
742
|
+
</div>
|
|
743
|
+
|
|
744
|
+
<div class="color-sections">
|
|
745
|
+
<div class="color-section">
|
|
746
|
+
<h4>Primary Color</h4>
|
|
747
|
+
<ColorPicker
|
|
748
|
+
:color="brandColors.primary"
|
|
749
|
+
@update:color="(color) => updateBrandColor('primary', color)"
|
|
750
|
+
/>
|
|
751
|
+
<div class="color-details">
|
|
752
|
+
<p>
|
|
753
|
+
{{ brandColors.primary.name }}({{ brandColors.primary.weight }})
|
|
754
|
+
</p>
|
|
755
|
+
<p class="hex">{{ brandColors.primary.hex }}</p>
|
|
756
|
+
</div>
|
|
757
|
+
</div>
|
|
758
|
+
|
|
759
|
+
<div class="color-section">
|
|
760
|
+
<h4>Secondary Color</h4>
|
|
761
|
+
<ColorPicker
|
|
762
|
+
:color="brandColors.secondary"
|
|
763
|
+
@update:color="(color) => updateBrandColor('secondary', color)"
|
|
764
|
+
/>
|
|
765
|
+
<div class="color-details">
|
|
766
|
+
<p>
|
|
767
|
+
{{ brandColors.secondary.name }}({{ brandColors.secondary.weight }})
|
|
768
|
+
</p>
|
|
769
|
+
<p class="hex">{{ brandColors.secondary.hex }}</p>
|
|
770
|
+
</div>
|
|
771
|
+
</div>
|
|
772
|
+
|
|
773
|
+
<div class="color-section">
|
|
774
|
+
<h4>Accent Color</h4>
|
|
775
|
+
<ColorPicker
|
|
776
|
+
:color="brandColors.accent"
|
|
777
|
+
@update:color="(color) => updateBrandColor('accent', color)"
|
|
778
|
+
/>
|
|
779
|
+
<div class="color-details">
|
|
780
|
+
<p>{{ brandColors.accent.name }}({{ brandColors.accent.weight }})</p>
|
|
781
|
+
<p class="hex">{{ brandColors.accent.hex }}</p>
|
|
782
|
+
</div>
|
|
783
|
+
</div>
|
|
784
|
+
|
|
785
|
+
<div class="color-section">
|
|
786
|
+
<h4>Neutral Color</h4>
|
|
787
|
+
<ColorPicker
|
|
788
|
+
:color="brandColors.neutral"
|
|
789
|
+
@update:color="(color) => updateBrandColor('neutral', color)"
|
|
790
|
+
/>
|
|
791
|
+
<div class="color-details">
|
|
792
|
+
<p>
|
|
793
|
+
{{ brandColors.neutral.name }}({{ brandColors.neutral.weight }})
|
|
794
|
+
</p>
|
|
795
|
+
<p class="hex">{{ brandColors.neutral.hex }}</p>
|
|
796
|
+
</div>
|
|
797
|
+
</div>
|
|
798
|
+
</div>
|
|
799
|
+
|
|
800
|
+
<div class="brand-preview">
|
|
801
|
+
<h4>Brand Preview</h4>
|
|
802
|
+
<div class="preview-card">
|
|
803
|
+
<div
|
|
804
|
+
class="preview-header"
|
|
805
|
+
:style="{ backgroundColor: brandColors.primary.hex }"
|
|
806
|
+
>
|
|
807
|
+
<h5>Your Brand</h5>
|
|
808
|
+
</div>
|
|
809
|
+
<div class="preview-content">
|
|
810
|
+
<p>This is how your brand colors work together.</p>
|
|
811
|
+
<button
|
|
812
|
+
class="preview-btn"
|
|
813
|
+
:style="{
|
|
814
|
+
backgroundColor: brandColors.accent.hex,
|
|
815
|
+
color: brandColors.neutral.hex,
|
|
816
|
+
}"
|
|
817
|
+
>
|
|
818
|
+
Call to Action
|
|
819
|
+
</button>
|
|
820
|
+
</div>
|
|
821
|
+
</div>
|
|
822
|
+
</div>
|
|
823
|
+
|
|
824
|
+
<div class="css-output">
|
|
825
|
+
<h4>Generated CSS</h4>
|
|
826
|
+
<pre class="css-code">{{ generateCSS() }}</pre>
|
|
827
|
+
</div>
|
|
828
|
+
</div>
|
|
829
|
+
</template>
|
|
830
|
+
|
|
831
|
+
<style module>
|
|
832
|
+
.brand-selector {
|
|
833
|
+
padding: 24px;
|
|
834
|
+
max-width: 800px;
|
|
835
|
+
background: #ffffff;
|
|
836
|
+
border-radius: 12px;
|
|
837
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
.selector-header {
|
|
841
|
+
margin-bottom: 32px;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
.selector-header h3 {
|
|
845
|
+
font-size: 24px;
|
|
846
|
+
font-weight: 600;
|
|
847
|
+
color: #1a202c;
|
|
848
|
+
margin: 0 0 8px 0;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
.selector-header p {
|
|
852
|
+
color: #718096;
|
|
853
|
+
margin: 0;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.color-sections {
|
|
857
|
+
display: grid;
|
|
858
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
859
|
+
gap: 24px;
|
|
860
|
+
margin-bottom: 32px;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
.color-section {
|
|
864
|
+
text-align: center;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
.color-section h4 {
|
|
868
|
+
font-size: 16px;
|
|
869
|
+
font-weight: 500;
|
|
870
|
+
color: #2d3748;
|
|
871
|
+
margin: 0 0 16px 0;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
.color-details {
|
|
875
|
+
margin-top: 12px;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
.color-details p {
|
|
879
|
+
margin: 0 0 4px 0;
|
|
880
|
+
font-size: 14px;
|
|
881
|
+
color: #4a5568;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
.color-details .hex {
|
|
885
|
+
font-family: monospace;
|
|
886
|
+
font-size: 12px;
|
|
887
|
+
color: #718096;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
.brand-preview {
|
|
891
|
+
margin-bottom: 32px;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.brand-preview h4 {
|
|
895
|
+
font-size: 18px;
|
|
896
|
+
font-weight: 500;
|
|
897
|
+
color: #2d3748;
|
|
898
|
+
margin: 0 0 16px 0;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
.preview-card {
|
|
902
|
+
border-radius: 8px;
|
|
903
|
+
overflow: hidden;
|
|
904
|
+
border: 1px solid #e2e8f0;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
.preview-header {
|
|
908
|
+
padding: 16px;
|
|
909
|
+
color: white;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
.preview-header h5 {
|
|
913
|
+
margin: 0;
|
|
914
|
+
font-size: 18px;
|
|
915
|
+
font-weight: 600;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
.preview-content {
|
|
919
|
+
padding: 16px;
|
|
920
|
+
background: #f7fafc;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
.preview-content p {
|
|
924
|
+
margin: 0 0 16px 0;
|
|
925
|
+
color: #4a5568;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
.preview-btn {
|
|
929
|
+
padding: 8px 16px;
|
|
930
|
+
border: none;
|
|
931
|
+
border-radius: 6px;
|
|
932
|
+
font-weight: 500;
|
|
933
|
+
cursor: pointer;
|
|
934
|
+
transition: opacity 0.2s ease;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
.preview-btn:hover {
|
|
938
|
+
opacity: 0.9;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
.css-output h4 {
|
|
942
|
+
font-size: 18px;
|
|
943
|
+
font-weight: 500;
|
|
944
|
+
color: #2d3748;
|
|
945
|
+
margin: 0 0 16px 0;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
.css-code {
|
|
949
|
+
background: #1a202c;
|
|
950
|
+
color: #e2e8f0;
|
|
951
|
+
padding: 16px;
|
|
952
|
+
border-radius: 8px;
|
|
953
|
+
font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
|
|
954
|
+
font-size: 14px;
|
|
955
|
+
line-height: 1.5;
|
|
956
|
+
overflow-x: auto;
|
|
957
|
+
margin: 0;
|
|
958
|
+
}
|
|
959
|
+
</style>
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
### Disabled State Example
|
|
963
|
+
|
|
964
|
+
```vue
|
|
965
|
+
<script setup lang="ts">
|
|
966
|
+
import { ref } from "vue";
|
|
967
|
+
import { ColorPicker, colorPickerColors } from "@umbra-ui/core";
|
|
968
|
+
import type { Color } from "@umbra-ui/core";
|
|
969
|
+
|
|
970
|
+
const selectedColor = ref<Color>(colorPickerColors.blue500);
|
|
971
|
+
const isDisabled = ref(false);
|
|
972
|
+
|
|
973
|
+
const toggleDisabled = () => {
|
|
974
|
+
isDisabled.value = !isDisabled.value;
|
|
975
|
+
};
|
|
976
|
+
</script>
|
|
977
|
+
|
|
978
|
+
<template>
|
|
979
|
+
<div class="disabled-example">
|
|
980
|
+
<h3>Disabled State</h3>
|
|
981
|
+
|
|
982
|
+
<div class="controls">
|
|
983
|
+
<button @click="toggleDisabled" class="toggle-btn">
|
|
984
|
+
{{ isDisabled ? "Enable" : "Disable" }} Color Picker
|
|
985
|
+
</button>
|
|
986
|
+
</div>
|
|
987
|
+
|
|
988
|
+
<ColorPicker
|
|
989
|
+
v-model:color="selectedColor"
|
|
990
|
+
:prevent-popup="isDisabled"
|
|
991
|
+
:dot-size="28"
|
|
992
|
+
:dot-border-width="2"
|
|
993
|
+
/>
|
|
994
|
+
|
|
995
|
+
<div class="status">
|
|
996
|
+
<p>Status: {{ isDisabled ? "Disabled" : "Enabled" }}</p>
|
|
997
|
+
<p>Selected: {{ selectedColor.name }}({{ selectedColor.weight }})</p>
|
|
998
|
+
</div>
|
|
999
|
+
</div>
|
|
1000
|
+
</template>
|
|
1001
|
+
|
|
1002
|
+
<style module>
|
|
1003
|
+
.disabled-example {
|
|
1004
|
+
padding: 24px;
|
|
1005
|
+
max-width: 400px;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
.controls {
|
|
1009
|
+
margin-bottom: 20px;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
.toggle-btn {
|
|
1013
|
+
padding: 8px 16px;
|
|
1014
|
+
background: #4299e1;
|
|
1015
|
+
color: white;
|
|
1016
|
+
border: none;
|
|
1017
|
+
border-radius: 6px;
|
|
1018
|
+
cursor: pointer;
|
|
1019
|
+
font-weight: 500;
|
|
1020
|
+
transition: background 0.2s ease;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
.toggle-btn:hover {
|
|
1024
|
+
background: #3182ce;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
.status {
|
|
1028
|
+
margin-top: 20px;
|
|
1029
|
+
padding: 16px;
|
|
1030
|
+
background: #f7fafc;
|
|
1031
|
+
border-radius: 8px;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
.status p {
|
|
1035
|
+
margin: 0 0 8px 0;
|
|
1036
|
+
color: #4a5568;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
.status p:last-child {
|
|
1040
|
+
margin-bottom: 0;
|
|
1041
|
+
}
|
|
1042
|
+
</style>
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
## Advanced Usage
|
|
1046
|
+
|
|
1047
|
+
### Custom Color Palette
|
|
1048
|
+
|
|
1049
|
+
```vue
|
|
1050
|
+
<script setup lang="ts">
|
|
1051
|
+
import { ref } from "vue";
|
|
1052
|
+
import { ColorPicker } from "@umbra-ui/core";
|
|
1053
|
+
import type { Color } from "@umbra-ui/core";
|
|
1054
|
+
|
|
1055
|
+
// Define custom colors
|
|
1056
|
+
const customColors: Color[] = [
|
|
1057
|
+
{ name: "Brand Blue", hex: "#1e40af", weight: null },
|
|
1058
|
+
{ name: "Brand Green", hex: "#059669", weight: null },
|
|
1059
|
+
{ name: "Brand Orange", hex: "#ea580c", weight: null },
|
|
1060
|
+
{ name: "Brand Purple", hex: "#7c3aed", weight: null },
|
|
1061
|
+
{ name: "Brand Pink", hex: "#db2777", weight: null },
|
|
1062
|
+
{ name: "Brand Teal", hex: "#0d9488", weight: null },
|
|
1063
|
+
];
|
|
1064
|
+
|
|
1065
|
+
const selectedColor = ref<Color>(customColors[0]);
|
|
1066
|
+
|
|
1067
|
+
const handleColorChange = (color: Color) => {
|
|
1068
|
+
console.log("Custom color selected:", color);
|
|
1069
|
+
};
|
|
1070
|
+
</script>
|
|
1071
|
+
|
|
1072
|
+
<template>
|
|
1073
|
+
<div class="custom-palette">
|
|
1074
|
+
<h3>Custom Color Palette</h3>
|
|
1075
|
+
|
|
1076
|
+
<ColorPicker
|
|
1077
|
+
v-model:color="selectedColor"
|
|
1078
|
+
@update:color="handleColorChange"
|
|
1079
|
+
/>
|
|
1080
|
+
|
|
1081
|
+
<div class="custom-colors">
|
|
1082
|
+
<h4>Available Custom Colors</h4>
|
|
1083
|
+
<div class="color-grid">
|
|
1084
|
+
<div
|
|
1085
|
+
v-for="color in customColors"
|
|
1086
|
+
:key="color.hex"
|
|
1087
|
+
class="color-item"
|
|
1088
|
+
:class="{ active: selectedColor.hex === color.hex }"
|
|
1089
|
+
@click="selectedColor = color"
|
|
1090
|
+
>
|
|
1091
|
+
<div class="color-swatch" :style="{ backgroundColor: color.hex }" />
|
|
1092
|
+
<p class="color-label">{{ color.name }}</p>
|
|
1093
|
+
</div>
|
|
1094
|
+
</div>
|
|
1095
|
+
</div>
|
|
1096
|
+
</div>
|
|
1097
|
+
</template>
|
|
1098
|
+
|
|
1099
|
+
<style module>
|
|
1100
|
+
.custom-palette {
|
|
1101
|
+
padding: 24px;
|
|
1102
|
+
max-width: 500px;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
.custom-colors {
|
|
1106
|
+
margin-top: 24px;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
.custom-colors h4 {
|
|
1110
|
+
font-size: 16px;
|
|
1111
|
+
font-weight: 500;
|
|
1112
|
+
color: #2d3748;
|
|
1113
|
+
margin: 0 0 16px 0;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
.color-grid {
|
|
1117
|
+
display: grid;
|
|
1118
|
+
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
|
|
1119
|
+
gap: 16px;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
.color-item {
|
|
1123
|
+
text-align: center;
|
|
1124
|
+
cursor: pointer;
|
|
1125
|
+
padding: 12px;
|
|
1126
|
+
border-radius: 8px;
|
|
1127
|
+
transition: background 0.2s ease;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
.color-item:hover {
|
|
1131
|
+
background: #f7fafc;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
.color-item.active {
|
|
1135
|
+
background: #e6fffa;
|
|
1136
|
+
border: 2px solid #38b2ac;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
.color-swatch {
|
|
1140
|
+
width: 40px;
|
|
1141
|
+
height: 40px;
|
|
1142
|
+
border-radius: 50%;
|
|
1143
|
+
margin: 0 auto 8px;
|
|
1144
|
+
border: 2px solid #e2e8f0;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
.color-label {
|
|
1148
|
+
font-size: 12px;
|
|
1149
|
+
color: #4a5568;
|
|
1150
|
+
margin: 0;
|
|
1151
|
+
}
|
|
1152
|
+
</style>
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
### Color Accessibility Checker
|
|
1156
|
+
|
|
1157
|
+
```vue
|
|
1158
|
+
<script setup lang="ts">
|
|
1159
|
+
import { ref, computed } from "vue";
|
|
1160
|
+
import { ColorPicker, colorPickerColors } from "@umbra-ui/core";
|
|
1161
|
+
import type { Color } from "@umbra-ui/core";
|
|
1162
|
+
|
|
1163
|
+
const selectedColor = ref<Color>(colorPickerColors.blue500);
|
|
1164
|
+
const backgroundColor = ref<Color>(colorPickerColors.white);
|
|
1165
|
+
|
|
1166
|
+
// Simple contrast ratio calculation
|
|
1167
|
+
const getContrastRatio = (color1: string, color2: string) => {
|
|
1168
|
+
const getLuminance = (hex: string) => {
|
|
1169
|
+
const rgb = parseInt(hex.slice(1), 16);
|
|
1170
|
+
const r = (rgb >> 16) & 0xff;
|
|
1171
|
+
const g = (rgb >> 8) & 0xff;
|
|
1172
|
+
const b = (rgb >> 0) & 0xff;
|
|
1173
|
+
|
|
1174
|
+
const [rs, gs, bs] = [r, g, b].map((c) => {
|
|
1175
|
+
c = c / 255;
|
|
1176
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
1177
|
+
});
|
|
1178
|
+
|
|
1179
|
+
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
|
|
1180
|
+
};
|
|
1181
|
+
|
|
1182
|
+
const lum1 = getLuminance(color1);
|
|
1183
|
+
const lum2 = getLuminance(color2);
|
|
1184
|
+
const brightest = Math.max(lum1, lum2);
|
|
1185
|
+
const darkest = Math.min(lum1, lum2);
|
|
1186
|
+
|
|
1187
|
+
return (brightest + 0.05) / (darkest + 0.05);
|
|
1188
|
+
};
|
|
1189
|
+
|
|
1190
|
+
const contrastRatio = computed(() => {
|
|
1191
|
+
return getContrastRatio(selectedColor.value.hex, backgroundColor.value.hex);
|
|
1192
|
+
});
|
|
1193
|
+
|
|
1194
|
+
const accessibilityLevel = computed(() => {
|
|
1195
|
+
const ratio = contrastRatio.value;
|
|
1196
|
+
if (ratio >= 7) return { level: "AAA", color: "#059669" };
|
|
1197
|
+
if (ratio >= 4.5) return { level: "AA", color: "#d97706" };
|
|
1198
|
+
if (ratio >= 3) return { level: "AA Large", color: "#dc2626" };
|
|
1199
|
+
return { level: "Fail", color: "#dc2626" };
|
|
1200
|
+
});
|
|
1201
|
+
</script>
|
|
1202
|
+
|
|
1203
|
+
<template>
|
|
1204
|
+
<div class="accessibility-checker">
|
|
1205
|
+
<h3>Color Accessibility Checker</h3>
|
|
1206
|
+
|
|
1207
|
+
<div class="color-inputs">
|
|
1208
|
+
<div class="color-input">
|
|
1209
|
+
<h4>Text Color</h4>
|
|
1210
|
+
<ColorPicker v-model:color="selectedColor" :dot-size="24" />
|
|
1211
|
+
</div>
|
|
1212
|
+
|
|
1213
|
+
<div class="color-input">
|
|
1214
|
+
<h4>Background Color</h4>
|
|
1215
|
+
<ColorPicker v-model:color="backgroundColor" :dot-size="24" />
|
|
1216
|
+
</div>
|
|
1217
|
+
</div>
|
|
1218
|
+
|
|
1219
|
+
<div class="preview-section">
|
|
1220
|
+
<h4>Preview</h4>
|
|
1221
|
+
<div
|
|
1222
|
+
class="preview-text"
|
|
1223
|
+
:style="{
|
|
1224
|
+
color: selectedColor.hex,
|
|
1225
|
+
backgroundColor: backgroundColor.hex,
|
|
1226
|
+
}"
|
|
1227
|
+
>
|
|
1228
|
+
This is how your text will look with these colors.
|
|
1229
|
+
</div>
|
|
1230
|
+
</div>
|
|
1231
|
+
|
|
1232
|
+
<div class="accessibility-results">
|
|
1233
|
+
<h4>Accessibility Results</h4>
|
|
1234
|
+
<div class="results-grid">
|
|
1235
|
+
<div class="result-item">
|
|
1236
|
+
<span class="result-label">Contrast Ratio:</span>
|
|
1237
|
+
<span class="result-value">{{ contrastRatio.toFixed(2) }}:1</span>
|
|
1238
|
+
</div>
|
|
1239
|
+
<div class="result-item">
|
|
1240
|
+
<span class="result-label">WCAG Level:</span>
|
|
1241
|
+
<span
|
|
1242
|
+
class="result-value"
|
|
1243
|
+
:style="{ color: accessibilityLevel.color }"
|
|
1244
|
+
>
|
|
1245
|
+
{{ accessibilityLevel.level }}
|
|
1246
|
+
</span>
|
|
1247
|
+
</div>
|
|
1248
|
+
</div>
|
|
1249
|
+
|
|
1250
|
+
<div class="recommendations">
|
|
1251
|
+
<h5>Recommendations:</h5>
|
|
1252
|
+
<ul>
|
|
1253
|
+
<li v-if="contrastRatio < 4.5">
|
|
1254
|
+
Consider using a darker text color or lighter background for better
|
|
1255
|
+
readability
|
|
1256
|
+
</li>
|
|
1257
|
+
<li v-if="contrastRatio >= 4.5 && contrastRatio < 7">
|
|
1258
|
+
Good contrast! Consider aiming for AAA level (7:1) for even better
|
|
1259
|
+
accessibility
|
|
1260
|
+
</li>
|
|
1261
|
+
<li v-if="contrastRatio >= 7">
|
|
1262
|
+
Excellent contrast! This meets WCAG AAA standards
|
|
1263
|
+
</li>
|
|
1264
|
+
</ul>
|
|
1265
|
+
</div>
|
|
1266
|
+
</div>
|
|
1267
|
+
</div>
|
|
1268
|
+
</template>
|
|
1269
|
+
|
|
1270
|
+
<style module>
|
|
1271
|
+
.accessibility-checker {
|
|
1272
|
+
padding: 24px;
|
|
1273
|
+
max-width: 600px;
|
|
1274
|
+
background: #ffffff;
|
|
1275
|
+
border-radius: 12px;
|
|
1276
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
.color-inputs {
|
|
1280
|
+
display: grid;
|
|
1281
|
+
grid-template-columns: 1fr 1fr;
|
|
1282
|
+
gap: 24px;
|
|
1283
|
+
margin-bottom: 32px;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
.color-input {
|
|
1287
|
+
text-align: center;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
.color-input h4 {
|
|
1291
|
+
font-size: 16px;
|
|
1292
|
+
font-weight: 500;
|
|
1293
|
+
color: #2d3748;
|
|
1294
|
+
margin: 0 0 16px 0;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
.preview-section {
|
|
1298
|
+
margin-bottom: 32px;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
.preview-section h4 {
|
|
1302
|
+
font-size: 16px;
|
|
1303
|
+
font-weight: 500;
|
|
1304
|
+
color: #2d3748;
|
|
1305
|
+
margin: 0 0 16px 0;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
.preview-text {
|
|
1309
|
+
padding: 24px;
|
|
1310
|
+
border-radius: 8px;
|
|
1311
|
+
font-size: 18px;
|
|
1312
|
+
font-weight: 500;
|
|
1313
|
+
text-align: center;
|
|
1314
|
+
border: 2px solid #e2e8f0;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
.accessibility-results h4 {
|
|
1318
|
+
font-size: 16px;
|
|
1319
|
+
font-weight: 500;
|
|
1320
|
+
color: #2d3748;
|
|
1321
|
+
margin: 0 0 16px 0;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
.results-grid {
|
|
1325
|
+
display: grid;
|
|
1326
|
+
grid-template-columns: 1fr 1fr;
|
|
1327
|
+
gap: 16px;
|
|
1328
|
+
margin-bottom: 24px;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
.result-item {
|
|
1332
|
+
display: flex;
|
|
1333
|
+
justify-content: space-between;
|
|
1334
|
+
align-items: center;
|
|
1335
|
+
padding: 12px;
|
|
1336
|
+
background: #f7fafc;
|
|
1337
|
+
border-radius: 6px;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
.result-label {
|
|
1341
|
+
font-weight: 500;
|
|
1342
|
+
color: #4a5568;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
.result-value {
|
|
1346
|
+
font-weight: 600;
|
|
1347
|
+
color: #2d3748;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
.recommendations {
|
|
1351
|
+
padding: 16px;
|
|
1352
|
+
background: #f0f9ff;
|
|
1353
|
+
border-radius: 8px;
|
|
1354
|
+
border-left: 4px solid #0ea5e9;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
.recommendations h5 {
|
|
1358
|
+
font-size: 14px;
|
|
1359
|
+
font-weight: 600;
|
|
1360
|
+
color: #0c4a6e;
|
|
1361
|
+
margin: 0 0 8px 0;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
.recommendations ul {
|
|
1365
|
+
margin: 0;
|
|
1366
|
+
padding-left: 20px;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
.recommendations li {
|
|
1370
|
+
font-size: 14px;
|
|
1371
|
+
color: #0c4a6e;
|
|
1372
|
+
margin-bottom: 4px;
|
|
1373
|
+
}
|
|
1374
|
+
</style>
|
|
1375
|
+
```
|
|
1376
|
+
|
|
1377
|
+
## Performance Considerations
|
|
1378
|
+
|
|
1379
|
+
- **Floating UI**: Smart positioning with automatic updates and cleanup
|
|
1380
|
+
- **Teleport**: Overlay and picker are teleported to body for proper z-index management
|
|
1381
|
+
- **Event Cleanup**: Proper cleanup of auto-update listeners on unmount
|
|
1382
|
+
- **Color Grid**: Efficient 8-column grid layout for optimal performance
|
|
1383
|
+
- **Computed Styles**: Dot styles are computed reactively for smooth animations
|
|
1384
|
+
|
|
1385
|
+
## Accessibility
|
|
1386
|
+
|
|
1387
|
+
- **Keyboard Navigation**: Support for keyboard interaction
|
|
1388
|
+
- **Screen Reader Support**: Proper ARIA labels and semantic structure
|
|
1389
|
+
- **Focus Management**: Focus is properly managed during interactions
|
|
1390
|
+
- **Color Information**: Displays color names, weights, and hex values
|
|
1391
|
+
- **High Contrast**: Supports high contrast mode with appropriate borders
|
|
1392
|
+
|
|
1393
|
+
## Browser Support
|
|
1394
|
+
|
|
1395
|
+
- **Modern Browsers**: Chrome 88+, Firefox 85+, Safari 14+, Edge 88+
|
|
1396
|
+
- **Mobile Browsers**: iOS Safari 14+, Chrome Mobile 88+
|
|
1397
|
+
- **CSS Features**: Uses CSS Grid and modern layout features
|
|
1398
|
+
- **JavaScript**: Requires ES2020+ support
|
|
1399
|
+
|
|
1400
|
+
## Troubleshooting
|
|
1401
|
+
|
|
1402
|
+
### Common Issues
|
|
1403
|
+
|
|
1404
|
+
1. **Picker not positioning correctly**: Ensure the trigger button has proper positioning context
|
|
1405
|
+
2. **Colors not displaying**: Check that the colors array is properly imported
|
|
1406
|
+
3. **Dot not updating**: Verify the v-model binding is correctly set up
|
|
1407
|
+
4. **Overlay not closing**: Ensure the overlay click handler is properly bound
|
|
1408
|
+
|
|
1409
|
+
### Debug Mode
|
|
1410
|
+
|
|
1411
|
+
```vue
|
|
1412
|
+
<script setup lang="ts">
|
|
1413
|
+
import { ref, watch } from "vue";
|
|
1414
|
+
import { ColorPicker } from "@umbra-ui/core";
|
|
1415
|
+
|
|
1416
|
+
const selectedColor = ref(null);
|
|
1417
|
+
|
|
1418
|
+
// Watch for changes
|
|
1419
|
+
watch(selectedColor, (newColor) => {
|
|
1420
|
+
console.log("Selected color changed:", newColor);
|
|
1421
|
+
});
|
|
1422
|
+
</script>
|
|
1423
|
+
```
|
|
1424
|
+
|
|
1425
|
+
## Migration Guide
|
|
1426
|
+
|
|
1427
|
+
### From v1 to v2
|
|
1428
|
+
|
|
1429
|
+
- `v-model` prop is now `v-model:color`
|
|
1430
|
+
- Event names have been updated to use kebab-case
|
|
1431
|
+
- Color system has been updated with comprehensive palette
|
|
1432
|
+
- Floating UI integration has been improved
|
|
1433
|
+
|
|
1434
|
+
### Breaking Changes
|
|
1435
|
+
|
|
1436
|
+
- Removed `value` prop in favor of `v-model:color`
|
|
1437
|
+
- Changed event names from camelCase to kebab-case
|
|
1438
|
+
- Updated color prop to use Color interface instead of string
|
|
1439
|
+
- Modified CSS class naming convention
|