@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,1115 @@
|
|
|
1
|
+
# CollectionPicker
|
|
2
|
+
|
|
3
|
+
A versatile collection picker component built with Vue 3 Composition API and TypeScript. The CollectionPicker provides an intuitive interface for selecting items from a collection with support for creating new items, customizable icons, and smart positioning using Floating UI.
|
|
4
|
+
|
|
5
|
+
## Installation/Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { CollectionPicker } from "@umbra-ui/core";
|
|
9
|
+
import type { CollectionItem } from "@umbra-ui/core";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Dependencies:**
|
|
13
|
+
|
|
14
|
+
- Vue 3.x
|
|
15
|
+
- @floating-ui/vue (for positioning)
|
|
16
|
+
- @umbra-ui/icons (for icon support)
|
|
17
|
+
- @umbra-ui/core (for IconButton)
|
|
18
|
+
|
|
19
|
+
## Basic Usage
|
|
20
|
+
|
|
21
|
+
```vue
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import { ref } from "vue";
|
|
24
|
+
import { CollectionPicker } from "@umbra-ui/core";
|
|
25
|
+
import type { CollectionItem } from "@umbra-ui/core";
|
|
26
|
+
|
|
27
|
+
const items = ref<CollectionItem[]>([
|
|
28
|
+
{ id: "1", title: "Project Alpha" },
|
|
29
|
+
{ id: "2", title: "Project Beta" },
|
|
30
|
+
{ id: "3", title: "Project Gamma" },
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
const selectedItem = ref<CollectionItem | null>(null);
|
|
34
|
+
|
|
35
|
+
const handleItemSelected = (item: CollectionItem) => {
|
|
36
|
+
console.log("Selected item:", item);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const handleItemCreate = (title: string) => {
|
|
40
|
+
const newItem: CollectionItem = {
|
|
41
|
+
id: Date.now().toString(),
|
|
42
|
+
title: title,
|
|
43
|
+
};
|
|
44
|
+
items.value.push(newItem);
|
|
45
|
+
selectedItem.value = newItem;
|
|
46
|
+
console.log("Created new item:", newItem);
|
|
47
|
+
};
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<template>
|
|
51
|
+
<div class="app">
|
|
52
|
+
<h2>Select a Project</h2>
|
|
53
|
+
|
|
54
|
+
<CollectionPicker
|
|
55
|
+
v-model:selected-item="selectedItem"
|
|
56
|
+
:items="items"
|
|
57
|
+
button-label="Choose Project"
|
|
58
|
+
header-label="Select a Project"
|
|
59
|
+
new-item-label="Create New Project"
|
|
60
|
+
@item-selected="handleItemSelected"
|
|
61
|
+
@item-create="handleItemCreate"
|
|
62
|
+
/>
|
|
63
|
+
|
|
64
|
+
<div v-if="selectedItem" class="selected-info">
|
|
65
|
+
<p>Selected: {{ selectedItem.title }}</p>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<style module>
|
|
71
|
+
.app {
|
|
72
|
+
padding: 24px;
|
|
73
|
+
max-width: 400px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.selected-info {
|
|
77
|
+
margin-top: 16px;
|
|
78
|
+
padding: 12px;
|
|
79
|
+
background: #f8f9fa;
|
|
80
|
+
border-radius: 6px;
|
|
81
|
+
}
|
|
82
|
+
</style>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Props
|
|
86
|
+
|
|
87
|
+
| Prop Name | Type | Required | Default | Description |
|
|
88
|
+
| -------------- | ------------------------ | -------- | ------------------ | --------------------------------------- |
|
|
89
|
+
| `items` | `CollectionItem[]` | Yes | `[]` | Array of items to display in the picker |
|
|
90
|
+
| `selectedItem` | `CollectionItem \| null` | No | `null` | Currently selected item |
|
|
91
|
+
| `loading` | `boolean` | No | `false` | Whether the picker is in loading state |
|
|
92
|
+
| `buttonLabel` | `string` | No | `"Select Item"` | Label for the trigger button |
|
|
93
|
+
| `headerLabel` | `string` | No | `"Choose an Item"` | Header text in the picker |
|
|
94
|
+
| `newItemLabel` | `string` | No | `"New Item"` | Label for the create new item option |
|
|
95
|
+
| `itemIcon` | `string` | No | `"note"` | Icon name for items |
|
|
96
|
+
| `newItemIcon` | `string` | No | `"circle-plus"` | Icon name for create new item |
|
|
97
|
+
| `allowCreate` | `boolean` | No | `true` | Whether to allow creating new items |
|
|
98
|
+
| `placeholder` | `string` | No | `"Enter name..."` | Placeholder text for new item input |
|
|
99
|
+
|
|
100
|
+
## CollectionItem Interface
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
interface CollectionItem {
|
|
104
|
+
id: string;
|
|
105
|
+
title: string;
|
|
106
|
+
[key: string]: any; // Allow additional properties
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### CollectionItem Properties
|
|
111
|
+
|
|
112
|
+
| Property | Type | Description |
|
|
113
|
+
| --------------- | -------- | ------------------------------ |
|
|
114
|
+
| `id` | `string` | Unique identifier for the item |
|
|
115
|
+
| `title` | `string` | Display text for the item |
|
|
116
|
+
| `[key: string]` | `any` | Additional custom properties |
|
|
117
|
+
|
|
118
|
+
## Events
|
|
119
|
+
|
|
120
|
+
| Event Name | Payload Type | Description |
|
|
121
|
+
| --------------------- | ------------------------ | ------------------------------------------ |
|
|
122
|
+
| `item-selected` | `CollectionItem` | Emitted when an item is selected |
|
|
123
|
+
| `item-create` | `string` | Emitted when a new item is created (title) |
|
|
124
|
+
| `update:selectedItem` | `CollectionItem \| null` | Emitted when the selected item changes |
|
|
125
|
+
|
|
126
|
+
## CSS Customization
|
|
127
|
+
|
|
128
|
+
### Layout Variables
|
|
129
|
+
|
|
130
|
+
```css
|
|
131
|
+
.collection-picker {
|
|
132
|
+
--picker-button-bg: #ffffff;
|
|
133
|
+
--picker-button-border: 1px solid #e9ecef;
|
|
134
|
+
--picker-button-hover-bg: #f8f9fa;
|
|
135
|
+
--picker-button-hover-border: 1px solid #dee2e6;
|
|
136
|
+
--picker-button-hover-shadow: rgba(0, 0, 0, 0.1);
|
|
137
|
+
--picker-button-hover-inset-shadow: rgba(255, 255, 255, 0.1);
|
|
138
|
+
--picker-button-selected-bg: #e3f2fd;
|
|
139
|
+
--picker-picker-bg: #ffffff;
|
|
140
|
+
--picker-picker-border: 1px solid #e9ecef;
|
|
141
|
+
--picker-picker-shadow: rgba(0, 0, 0, 0.1);
|
|
142
|
+
--picker-picker-inset-shadow: rgba(255, 255, 255, 0.1);
|
|
143
|
+
--picker-selection-bar-bg: #f8f9fa;
|
|
144
|
+
--picker-border-light: #e9ecef;
|
|
145
|
+
--picker-text-primary: #212529;
|
|
146
|
+
--picker-text-secondary: #6c757d;
|
|
147
|
+
--picker-bg-hover: #f8f9fa;
|
|
148
|
+
--picker-overlay-bg: rgba(0, 0, 0, 0.1);
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Container Styling
|
|
153
|
+
|
|
154
|
+
```css
|
|
155
|
+
.collection-picker {
|
|
156
|
+
display: flex;
|
|
157
|
+
flex-direction: column;
|
|
158
|
+
align-items: start;
|
|
159
|
+
gap: 0.235rem;
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Button Styling
|
|
164
|
+
|
|
165
|
+
```css
|
|
166
|
+
.collection-picker .button {
|
|
167
|
+
border-radius: 0.353rem;
|
|
168
|
+
padding: 0.588rem;
|
|
169
|
+
display: flex;
|
|
170
|
+
align-items: center;
|
|
171
|
+
justify-content: space-between;
|
|
172
|
+
cursor: default;
|
|
173
|
+
background-color: var(--picker-button-bg);
|
|
174
|
+
border: var(--picker-button-border);
|
|
175
|
+
transition: all 0.3s ease;
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Picker Styling
|
|
180
|
+
|
|
181
|
+
```css
|
|
182
|
+
.collection-picker .picker {
|
|
183
|
+
position: absolute;
|
|
184
|
+
background-color: var(--picker-picker-bg);
|
|
185
|
+
border-radius: 0.353rem;
|
|
186
|
+
min-width: 18.824rem;
|
|
187
|
+
overflow: hidden;
|
|
188
|
+
z-index: 1000;
|
|
189
|
+
box-shadow: var(--picker-picker-shadow);
|
|
190
|
+
border: var(--picker-picker-border);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Examples
|
|
195
|
+
|
|
196
|
+
### Project Selector
|
|
197
|
+
|
|
198
|
+
```vue
|
|
199
|
+
<script setup lang="ts">
|
|
200
|
+
import { ref } from "vue";
|
|
201
|
+
import { CollectionPicker } from "@umbra-ui/core";
|
|
202
|
+
import type { CollectionItem } from "@umbra-ui/core";
|
|
203
|
+
|
|
204
|
+
const projects = ref<CollectionItem[]>([
|
|
205
|
+
{ id: "1", title: "E-commerce Platform", status: "active" },
|
|
206
|
+
{ id: "2", title: "Mobile App", status: "development" },
|
|
207
|
+
{ id: "3", title: "API Service", status: "completed" },
|
|
208
|
+
{ id: "4", title: "Dashboard", status: "planning" },
|
|
209
|
+
]);
|
|
210
|
+
|
|
211
|
+
const selectedProject = ref<CollectionItem | null>(null);
|
|
212
|
+
|
|
213
|
+
const handleProjectSelected = (project: CollectionItem) => {
|
|
214
|
+
console.log("Selected project:", project);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const handleProjectCreate = (title: string) => {
|
|
218
|
+
const newProject: CollectionItem = {
|
|
219
|
+
id: Date.now().toString(),
|
|
220
|
+
title: title,
|
|
221
|
+
status: "planning",
|
|
222
|
+
};
|
|
223
|
+
projects.value.push(newProject);
|
|
224
|
+
selectedProject.value = newProject;
|
|
225
|
+
console.log("Created new project:", newProject);
|
|
226
|
+
};
|
|
227
|
+
</script>
|
|
228
|
+
|
|
229
|
+
<template>
|
|
230
|
+
<div class="project-selector">
|
|
231
|
+
<div class="selector-header">
|
|
232
|
+
<h3>Project Management</h3>
|
|
233
|
+
<p>Select or create a project to work on</p>
|
|
234
|
+
</div>
|
|
235
|
+
|
|
236
|
+
<CollectionPicker
|
|
237
|
+
v-model:selected-item="selectedProject"
|
|
238
|
+
:items="projects"
|
|
239
|
+
button-label="Choose Project"
|
|
240
|
+
header-label="Select a Project"
|
|
241
|
+
new-item-label="Create New Project"
|
|
242
|
+
item-icon="folder"
|
|
243
|
+
new-item-icon="plus"
|
|
244
|
+
placeholder="Enter project name..."
|
|
245
|
+
@item-selected="handleProjectSelected"
|
|
246
|
+
@item-create="handleProjectCreate"
|
|
247
|
+
/>
|
|
248
|
+
|
|
249
|
+
<div v-if="selectedProject" class="project-details">
|
|
250
|
+
<h4>{{ selectedProject.title }}</h4>
|
|
251
|
+
<p>Status: {{ selectedProject.status }}</p>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
</template>
|
|
255
|
+
|
|
256
|
+
<style module>
|
|
257
|
+
.project-selector {
|
|
258
|
+
padding: 24px;
|
|
259
|
+
max-width: 500px;
|
|
260
|
+
background: #ffffff;
|
|
261
|
+
border-radius: 12px;
|
|
262
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.selector-header {
|
|
266
|
+
margin-bottom: 24px;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.selector-header h3 {
|
|
270
|
+
font-size: 20px;
|
|
271
|
+
font-weight: 600;
|
|
272
|
+
color: #1a202c;
|
|
273
|
+
margin: 0 0 8px 0;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.selector-header p {
|
|
277
|
+
color: #718096;
|
|
278
|
+
margin: 0;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.project-details {
|
|
282
|
+
margin-top: 20px;
|
|
283
|
+
padding: 16px;
|
|
284
|
+
background: #f7fafc;
|
|
285
|
+
border-radius: 8px;
|
|
286
|
+
border-left: 4px solid #4299e1;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.project-details h4 {
|
|
290
|
+
font-size: 16px;
|
|
291
|
+
font-weight: 600;
|
|
292
|
+
color: #2d3748;
|
|
293
|
+
margin: 0 0 8px 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.project-details p {
|
|
297
|
+
color: #4a5568;
|
|
298
|
+
margin: 0;
|
|
299
|
+
}
|
|
300
|
+
</style>
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Category Picker
|
|
304
|
+
|
|
305
|
+
```vue
|
|
306
|
+
<script setup lang="ts">
|
|
307
|
+
import { ref } from "vue";
|
|
308
|
+
import { CollectionPicker } from "@umbra-ui/core";
|
|
309
|
+
import type { CollectionItem } from "@umbra-ui/core";
|
|
310
|
+
|
|
311
|
+
const categories = ref<CollectionItem[]>([
|
|
312
|
+
{ id: "1", title: "Technology", color: "#3b82f6", count: 15 },
|
|
313
|
+
{ id: "2", title: "Design", color: "#8b5cf6", count: 8 },
|
|
314
|
+
{ id: "3", title: "Business", color: "#10b981", count: 12 },
|
|
315
|
+
{ id: "4", title: "Marketing", color: "#f59e0b", count: 6 },
|
|
316
|
+
]);
|
|
317
|
+
|
|
318
|
+
const selectedCategory = ref<CollectionItem | null>(null);
|
|
319
|
+
|
|
320
|
+
const handleCategorySelected = (category: CollectionItem) => {
|
|
321
|
+
console.log("Selected category:", category);
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
const handleCategoryCreate = (title: string) => {
|
|
325
|
+
const newCategory: CollectionItem = {
|
|
326
|
+
id: Date.now().toString(),
|
|
327
|
+
title: title,
|
|
328
|
+
color: "#6b7280",
|
|
329
|
+
count: 0,
|
|
330
|
+
};
|
|
331
|
+
categories.value.push(newCategory);
|
|
332
|
+
selectedCategory.value = newCategory;
|
|
333
|
+
console.log("Created new category:", newCategory);
|
|
334
|
+
};
|
|
335
|
+
</script>
|
|
336
|
+
|
|
337
|
+
<template>
|
|
338
|
+
<div class="category-picker">
|
|
339
|
+
<div class="picker-header">
|
|
340
|
+
<h3>Content Categories</h3>
|
|
341
|
+
<p>Organize your content with categories</p>
|
|
342
|
+
</div>
|
|
343
|
+
|
|
344
|
+
<CollectionPicker
|
|
345
|
+
v-model:selected-item="selectedCategory"
|
|
346
|
+
:items="categories"
|
|
347
|
+
button-label="Select Category"
|
|
348
|
+
header-label="Choose a Category"
|
|
349
|
+
new-item-label="Add New Category"
|
|
350
|
+
item-icon="tag"
|
|
351
|
+
new-item-icon="tag-plus"
|
|
352
|
+
placeholder="Category name..."
|
|
353
|
+
@item-selected="handleCategorySelected"
|
|
354
|
+
@item-create="handleCategoryCreate"
|
|
355
|
+
/>
|
|
356
|
+
|
|
357
|
+
<div v-if="selectedCategory" class="category-info">
|
|
358
|
+
<div class="category-header">
|
|
359
|
+
<div
|
|
360
|
+
class="category-color"
|
|
361
|
+
:style="{ backgroundColor: selectedCategory.color }"
|
|
362
|
+
/>
|
|
363
|
+
<h4>{{ selectedCategory.title }}</h4>
|
|
364
|
+
</div>
|
|
365
|
+
<p>{{ selectedCategory.count }} items in this category</p>
|
|
366
|
+
</div>
|
|
367
|
+
</div>
|
|
368
|
+
</template>
|
|
369
|
+
|
|
370
|
+
<style module>
|
|
371
|
+
.category-picker {
|
|
372
|
+
padding: 24px;
|
|
373
|
+
max-width: 400px;
|
|
374
|
+
background: #ffffff;
|
|
375
|
+
border-radius: 12px;
|
|
376
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.picker-header {
|
|
380
|
+
margin-bottom: 24px;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.picker-header h3 {
|
|
384
|
+
font-size: 20px;
|
|
385
|
+
font-weight: 600;
|
|
386
|
+
color: #1a202c;
|
|
387
|
+
margin: 0 0 8px 0;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.picker-header p {
|
|
391
|
+
color: #718096;
|
|
392
|
+
margin: 0;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.category-info {
|
|
396
|
+
margin-top: 20px;
|
|
397
|
+
padding: 16px;
|
|
398
|
+
background: #f7fafc;
|
|
399
|
+
border-radius: 8px;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.category-header {
|
|
403
|
+
display: flex;
|
|
404
|
+
align-items: center;
|
|
405
|
+
gap: 12px;
|
|
406
|
+
margin-bottom: 8px;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.category-color {
|
|
410
|
+
width: 16px;
|
|
411
|
+
height: 16px;
|
|
412
|
+
border-radius: 50%;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.category-header h4 {
|
|
416
|
+
font-size: 16px;
|
|
417
|
+
font-weight: 600;
|
|
418
|
+
color: #2d3748;
|
|
419
|
+
margin: 0;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.category-info p {
|
|
423
|
+
color: #4a5568;
|
|
424
|
+
margin: 0;
|
|
425
|
+
font-size: 14px;
|
|
426
|
+
}
|
|
427
|
+
</style>
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Team Member Selector
|
|
431
|
+
|
|
432
|
+
```vue
|
|
433
|
+
<script setup lang="ts">
|
|
434
|
+
import { ref } from "vue";
|
|
435
|
+
import { CollectionPicker } from "@umbra-ui/core";
|
|
436
|
+
import type { CollectionItem } from "@umbra-ui/core";
|
|
437
|
+
|
|
438
|
+
const teamMembers = ref<CollectionItem[]>([
|
|
439
|
+
{ id: "1", title: "Alice Johnson", role: "Frontend Developer", avatar: "👩💻" },
|
|
440
|
+
{ id: "2", title: "Bob Smith", role: "Backend Developer", avatar: "👨💻" },
|
|
441
|
+
{ id: "3", title: "Carol Davis", role: "UI/UX Designer", avatar: "👩🎨" },
|
|
442
|
+
{ id: "4", title: "David Wilson", role: "Project Manager", avatar: "👨💼" },
|
|
443
|
+
]);
|
|
444
|
+
|
|
445
|
+
const selectedMember = ref<CollectionItem | null>(null);
|
|
446
|
+
|
|
447
|
+
const handleMemberSelected = (member: CollectionItem) => {
|
|
448
|
+
console.log("Selected team member:", member);
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
const handleMemberCreate = (title: string) => {
|
|
452
|
+
const newMember: CollectionItem = {
|
|
453
|
+
id: Date.now().toString(),
|
|
454
|
+
title: title,
|
|
455
|
+
role: "Team Member",
|
|
456
|
+
avatar: "👤",
|
|
457
|
+
};
|
|
458
|
+
teamMembers.value.push(newMember);
|
|
459
|
+
selectedMember.value = newMember;
|
|
460
|
+
console.log("Added new team member:", newMember);
|
|
461
|
+
};
|
|
462
|
+
</script>
|
|
463
|
+
|
|
464
|
+
<template>
|
|
465
|
+
<div class="team-selector">
|
|
466
|
+
<div class="selector-header">
|
|
467
|
+
<h3>Team Assignment</h3>
|
|
468
|
+
<p>Assign tasks to team members</p>
|
|
469
|
+
</div>
|
|
470
|
+
|
|
471
|
+
<CollectionPicker
|
|
472
|
+
v-model:selected-item="selectedMember"
|
|
473
|
+
:items="teamMembers"
|
|
474
|
+
button-label="Assign to Team Member"
|
|
475
|
+
header-label="Select Team Member"
|
|
476
|
+
new-item-label="Add New Member"
|
|
477
|
+
item-icon="user"
|
|
478
|
+
new-item-icon="user-plus"
|
|
479
|
+
placeholder="Member name..."
|
|
480
|
+
@item-selected="handleMemberSelected"
|
|
481
|
+
@item-create="handleMemberCreate"
|
|
482
|
+
/>
|
|
483
|
+
|
|
484
|
+
<div v-if="selectedMember" class="member-details">
|
|
485
|
+
<div class="member-header">
|
|
486
|
+
<span class="member-avatar">{{ selectedMember.avatar }}</span>
|
|
487
|
+
<div class="member-info">
|
|
488
|
+
<h4>{{ selectedMember.title }}</h4>
|
|
489
|
+
<p>{{ selectedMember.role }}</p>
|
|
490
|
+
</div>
|
|
491
|
+
</div>
|
|
492
|
+
</div>
|
|
493
|
+
</div>
|
|
494
|
+
</template>
|
|
495
|
+
|
|
496
|
+
<style module>
|
|
497
|
+
.team-selector {
|
|
498
|
+
padding: 24px;
|
|
499
|
+
max-width: 450px;
|
|
500
|
+
background: #ffffff;
|
|
501
|
+
border-radius: 12px;
|
|
502
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.selector-header {
|
|
506
|
+
margin-bottom: 24px;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.selector-header h3 {
|
|
510
|
+
font-size: 20px;
|
|
511
|
+
font-weight: 600;
|
|
512
|
+
color: #1a202c;
|
|
513
|
+
margin: 0 0 8px 0;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
.selector-header p {
|
|
517
|
+
color: #718096;
|
|
518
|
+
margin: 0;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.member-details {
|
|
522
|
+
margin-top: 20px;
|
|
523
|
+
padding: 16px;
|
|
524
|
+
background: #f7fafc;
|
|
525
|
+
border-radius: 8px;
|
|
526
|
+
border-left: 4px solid #4299e1;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.member-header {
|
|
530
|
+
display: flex;
|
|
531
|
+
align-items: center;
|
|
532
|
+
gap: 12px;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.member-avatar {
|
|
536
|
+
font-size: 24px;
|
|
537
|
+
width: 40px;
|
|
538
|
+
height: 40px;
|
|
539
|
+
display: flex;
|
|
540
|
+
align-items: center;
|
|
541
|
+
justify-content: center;
|
|
542
|
+
background: #e2e8f0;
|
|
543
|
+
border-radius: 50%;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.member-info h4 {
|
|
547
|
+
font-size: 16px;
|
|
548
|
+
font-weight: 600;
|
|
549
|
+
color: #2d3748;
|
|
550
|
+
margin: 0 0 4px 0;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
.member-info p {
|
|
554
|
+
color: #4a5568;
|
|
555
|
+
margin: 0;
|
|
556
|
+
font-size: 14px;
|
|
557
|
+
}
|
|
558
|
+
</style>
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### File Type Picker
|
|
562
|
+
|
|
563
|
+
```vue
|
|
564
|
+
<script setup lang="ts">
|
|
565
|
+
import { ref } from "vue";
|
|
566
|
+
import { CollectionPicker } from "@umbra-ui/core";
|
|
567
|
+
import type { CollectionItem } from "@umbra-ui/core";
|
|
568
|
+
|
|
569
|
+
const fileTypes = ref<CollectionItem[]>([
|
|
570
|
+
{ id: "1", title: "Documents", extension: ".doc,.docx,.pdf", icon: "📄" },
|
|
571
|
+
{ id: "2", title: "Images", extension: ".jpg,.png,.gif", icon: "🖼️" },
|
|
572
|
+
{ id: "3", title: "Videos", extension: ".mp4,.avi,.mov", icon: "🎥" },
|
|
573
|
+
{ id: "4", title: "Audio", extension: ".mp3,.wav,.flac", icon: "🎵" },
|
|
574
|
+
{ id: "5", title: "Archives", extension: ".zip,.rar,.7z", icon: "📦" },
|
|
575
|
+
]);
|
|
576
|
+
|
|
577
|
+
const selectedFileType = ref<CollectionItem | null>(null);
|
|
578
|
+
|
|
579
|
+
const handleFileTypeSelected = (fileType: CollectionItem) => {
|
|
580
|
+
console.log("Selected file type:", fileType);
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
const handleFileTypeCreate = (title: string) => {
|
|
584
|
+
const newFileType: CollectionItem = {
|
|
585
|
+
id: Date.now().toString(),
|
|
586
|
+
title: title,
|
|
587
|
+
extension: ".*",
|
|
588
|
+
icon: "📁",
|
|
589
|
+
};
|
|
590
|
+
fileTypes.value.push(newFileType);
|
|
591
|
+
selectedFileType.value = newFileType;
|
|
592
|
+
console.log("Created new file type:", newFileType);
|
|
593
|
+
};
|
|
594
|
+
</script>
|
|
595
|
+
|
|
596
|
+
<template>
|
|
597
|
+
<div class="file-type-picker">
|
|
598
|
+
<div class="picker-header">
|
|
599
|
+
<h3>File Type Filter</h3>
|
|
600
|
+
<p>Filter files by type</p>
|
|
601
|
+
</div>
|
|
602
|
+
|
|
603
|
+
<CollectionPicker
|
|
604
|
+
v-model:selected-item="selectedFileType"
|
|
605
|
+
:items="fileTypes"
|
|
606
|
+
button-label="Select File Type"
|
|
607
|
+
header-label="Choose File Type"
|
|
608
|
+
new-item-label="Add Custom Type"
|
|
609
|
+
item-icon="file"
|
|
610
|
+
new-item-icon="file-plus"
|
|
611
|
+
placeholder="File type name..."
|
|
612
|
+
@item-selected="handleFileTypeSelected"
|
|
613
|
+
@item-create="handleFileTypeCreate"
|
|
614
|
+
/>
|
|
615
|
+
|
|
616
|
+
<div v-if="selectedFileType" class="file-type-info">
|
|
617
|
+
<div class="file-type-header">
|
|
618
|
+
<span class="file-type-icon">{{ selectedFileType.icon }}</span>
|
|
619
|
+
<div class="file-type-details">
|
|
620
|
+
<h4>{{ selectedFileType.title }}</h4>
|
|
621
|
+
<p>Extensions: {{ selectedFileType.extension }}</p>
|
|
622
|
+
</div>
|
|
623
|
+
</div>
|
|
624
|
+
</div>
|
|
625
|
+
</div>
|
|
626
|
+
</template>
|
|
627
|
+
|
|
628
|
+
<style module>
|
|
629
|
+
.file-type-picker {
|
|
630
|
+
padding: 24px;
|
|
631
|
+
max-width: 400px;
|
|
632
|
+
background: #ffffff;
|
|
633
|
+
border-radius: 12px;
|
|
634
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
.picker-header {
|
|
638
|
+
margin-bottom: 24px;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
.picker-header h3 {
|
|
642
|
+
font-size: 20px;
|
|
643
|
+
font-weight: 600;
|
|
644
|
+
color: #1a202c;
|
|
645
|
+
margin: 0 0 8px 0;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
.picker-header p {
|
|
649
|
+
color: #718096;
|
|
650
|
+
margin: 0;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
.file-type-info {
|
|
654
|
+
margin-top: 20px;
|
|
655
|
+
padding: 16px;
|
|
656
|
+
background: #f7fafc;
|
|
657
|
+
border-radius: 8px;
|
|
658
|
+
border-left: 4px solid #10b981;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.file-type-header {
|
|
662
|
+
display: flex;
|
|
663
|
+
align-items: center;
|
|
664
|
+
gap: 12px;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.file-type-icon {
|
|
668
|
+
font-size: 24px;
|
|
669
|
+
width: 40px;
|
|
670
|
+
height: 40px;
|
|
671
|
+
display: flex;
|
|
672
|
+
align-items: center;
|
|
673
|
+
justify-content: center;
|
|
674
|
+
background: #d1fae5;
|
|
675
|
+
border-radius: 8px;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
.file-type-details h4 {
|
|
679
|
+
font-size: 16px;
|
|
680
|
+
font-weight: 600;
|
|
681
|
+
color: #2d3748;
|
|
682
|
+
margin: 0 0 4px 0;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.file-type-details p {
|
|
686
|
+
color: #4a5568;
|
|
687
|
+
margin: 0;
|
|
688
|
+
font-size: 14px;
|
|
689
|
+
}
|
|
690
|
+
</style>
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
### Loading State Example
|
|
694
|
+
|
|
695
|
+
```vue
|
|
696
|
+
<script setup lang="ts">
|
|
697
|
+
import { ref, onMounted } from "vue";
|
|
698
|
+
import { CollectionPicker } from "@umbra-ui/core";
|
|
699
|
+
import type { CollectionItem } from "@umbra-ui/core";
|
|
700
|
+
|
|
701
|
+
const items = ref<CollectionItem[]>([]);
|
|
702
|
+
const selectedItem = ref<CollectionItem | null>(null);
|
|
703
|
+
const loading = ref(true);
|
|
704
|
+
|
|
705
|
+
// Simulate loading data
|
|
706
|
+
onMounted(async () => {
|
|
707
|
+
// Simulate API call
|
|
708
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
709
|
+
|
|
710
|
+
items.value = [
|
|
711
|
+
{ id: "1", title: "Item 1" },
|
|
712
|
+
{ id: "2", title: "Item 2" },
|
|
713
|
+
{ id: "3", title: "Item 3" },
|
|
714
|
+
];
|
|
715
|
+
|
|
716
|
+
loading.value = false;
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
const handleItemSelected = (item: CollectionItem) => {
|
|
720
|
+
console.log("Selected item:", item);
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
const handleItemCreate = (title: string) => {
|
|
724
|
+
const newItem: CollectionItem = {
|
|
725
|
+
id: Date.now().toString(),
|
|
726
|
+
title: title,
|
|
727
|
+
};
|
|
728
|
+
items.value.push(newItem);
|
|
729
|
+
selectedItem.value = newItem;
|
|
730
|
+
console.log("Created new item:", newItem);
|
|
731
|
+
};
|
|
732
|
+
</script>
|
|
733
|
+
|
|
734
|
+
<template>
|
|
735
|
+
<div class="loading-example">
|
|
736
|
+
<h3>Loading State Example</h3>
|
|
737
|
+
|
|
738
|
+
<CollectionPicker
|
|
739
|
+
v-model:selected-item="selectedItem"
|
|
740
|
+
:items="items"
|
|
741
|
+
:loading="loading"
|
|
742
|
+
button-label="Select Item"
|
|
743
|
+
header-label="Choose an Item"
|
|
744
|
+
new-item-label="Create New Item"
|
|
745
|
+
@item-selected="handleItemSelected"
|
|
746
|
+
@item-create="handleItemCreate"
|
|
747
|
+
/>
|
|
748
|
+
|
|
749
|
+
<div v-if="loading" class="loading-message">
|
|
750
|
+
<p>Loading items...</p>
|
|
751
|
+
</div>
|
|
752
|
+
</div>
|
|
753
|
+
</template>
|
|
754
|
+
|
|
755
|
+
<style module>
|
|
756
|
+
.loading-example {
|
|
757
|
+
padding: 24px;
|
|
758
|
+
max-width: 400px;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
.loading-message {
|
|
762
|
+
margin-top: 16px;
|
|
763
|
+
padding: 12px;
|
|
764
|
+
background: #f8f9fa;
|
|
765
|
+
border-radius: 6px;
|
|
766
|
+
text-align: center;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.loading-message p {
|
|
770
|
+
color: #6c757d;
|
|
771
|
+
margin: 0;
|
|
772
|
+
}
|
|
773
|
+
</style>
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
## Advanced Usage
|
|
777
|
+
|
|
778
|
+
### Custom Item Properties
|
|
779
|
+
|
|
780
|
+
```vue
|
|
781
|
+
<script setup lang="ts">
|
|
782
|
+
import { ref } from "vue";
|
|
783
|
+
import { CollectionPicker } from "@umbra-ui/core";
|
|
784
|
+
import type { CollectionItem } from "@umbra-ui/core";
|
|
785
|
+
|
|
786
|
+
// Extend the base interface for custom properties
|
|
787
|
+
interface CustomItem extends CollectionItem {
|
|
788
|
+
description: string;
|
|
789
|
+
priority: "low" | "medium" | "high";
|
|
790
|
+
tags: string[];
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
const items = ref<CustomItem[]>([
|
|
794
|
+
{
|
|
795
|
+
id: "1",
|
|
796
|
+
title: "Bug Fix",
|
|
797
|
+
description: "Fix critical authentication bug",
|
|
798
|
+
priority: "high",
|
|
799
|
+
tags: ["bug", "auth"],
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
id: "2",
|
|
803
|
+
title: "Feature Request",
|
|
804
|
+
description: "Add dark mode support",
|
|
805
|
+
priority: "medium",
|
|
806
|
+
tags: ["feature", "ui"],
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
id: "3",
|
|
810
|
+
title: "Documentation",
|
|
811
|
+
description: "Update API documentation",
|
|
812
|
+
priority: "low",
|
|
813
|
+
tags: ["docs", "api"],
|
|
814
|
+
},
|
|
815
|
+
]);
|
|
816
|
+
|
|
817
|
+
const selectedItem = ref<CustomItem | null>(null);
|
|
818
|
+
|
|
819
|
+
const handleItemSelected = (item: CustomItem) => {
|
|
820
|
+
console.log("Selected item with custom properties:", item);
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
const handleItemCreate = (title: string) => {
|
|
824
|
+
const newItem: CustomItem = {
|
|
825
|
+
id: Date.now().toString(),
|
|
826
|
+
title: title,
|
|
827
|
+
description: "New item",
|
|
828
|
+
priority: "medium",
|
|
829
|
+
tags: [],
|
|
830
|
+
};
|
|
831
|
+
items.value.push(newItem);
|
|
832
|
+
selectedItem.value = newItem;
|
|
833
|
+
};
|
|
834
|
+
</script>
|
|
835
|
+
|
|
836
|
+
<template>
|
|
837
|
+
<div class="custom-properties">
|
|
838
|
+
<CollectionPicker
|
|
839
|
+
v-model:selected-item="selectedItem"
|
|
840
|
+
:items="items"
|
|
841
|
+
button-label="Select Task"
|
|
842
|
+
header-label="Choose a Task"
|
|
843
|
+
new-item-label="Create New Task"
|
|
844
|
+
item-icon="checklist"
|
|
845
|
+
new-item-icon="plus"
|
|
846
|
+
@item-selected="handleItemSelected"
|
|
847
|
+
@item-create="handleItemCreate"
|
|
848
|
+
/>
|
|
849
|
+
|
|
850
|
+
<div v-if="selectedItem" class="item-details">
|
|
851
|
+
<h4>{{ selectedItem.title }}</h4>
|
|
852
|
+
<p>{{ selectedItem.description }}</p>
|
|
853
|
+
<div class="item-meta">
|
|
854
|
+
<span class="priority" :class="`priority-${selectedItem.priority}`">
|
|
855
|
+
{{ selectedItem.priority }}
|
|
856
|
+
</span>
|
|
857
|
+
<div class="tags">
|
|
858
|
+
<span v-for="tag in selectedItem.tags" :key="tag" class="tag">
|
|
859
|
+
{{ tag }}
|
|
860
|
+
</span>
|
|
861
|
+
</div>
|
|
862
|
+
</div>
|
|
863
|
+
</div>
|
|
864
|
+
</div>
|
|
865
|
+
</template>
|
|
866
|
+
|
|
867
|
+
<style module>
|
|
868
|
+
.custom-properties {
|
|
869
|
+
padding: 24px;
|
|
870
|
+
max-width: 500px;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
.item-details {
|
|
874
|
+
margin-top: 20px;
|
|
875
|
+
padding: 16px;
|
|
876
|
+
background: #f7fafc;
|
|
877
|
+
border-radius: 8px;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.item-details h4 {
|
|
881
|
+
font-size: 16px;
|
|
882
|
+
font-weight: 600;
|
|
883
|
+
color: #2d3748;
|
|
884
|
+
margin: 0 0 8px 0;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
.item-details p {
|
|
888
|
+
color: #4a5568;
|
|
889
|
+
margin: 0 0 12px 0;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
.item-meta {
|
|
893
|
+
display: flex;
|
|
894
|
+
align-items: center;
|
|
895
|
+
gap: 12px;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
.priority {
|
|
899
|
+
padding: 4px 8px;
|
|
900
|
+
border-radius: 4px;
|
|
901
|
+
font-size: 12px;
|
|
902
|
+
font-weight: 500;
|
|
903
|
+
text-transform: uppercase;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
.priority-low {
|
|
907
|
+
background: #d1fae5;
|
|
908
|
+
color: #065f46;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
.priority-medium {
|
|
912
|
+
background: #fef3c7;
|
|
913
|
+
color: #92400e;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
.priority-high {
|
|
917
|
+
background: #fee2e2;
|
|
918
|
+
color: #991b1b;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
.tags {
|
|
922
|
+
display: flex;
|
|
923
|
+
gap: 4px;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
.tag {
|
|
927
|
+
padding: 2px 6px;
|
|
928
|
+
background: #e5e7eb;
|
|
929
|
+
color: #374151;
|
|
930
|
+
border-radius: 3px;
|
|
931
|
+
font-size: 11px;
|
|
932
|
+
}
|
|
933
|
+
</style>
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
### Integration with API
|
|
937
|
+
|
|
938
|
+
```vue
|
|
939
|
+
<script setup lang="ts">
|
|
940
|
+
import { ref, onMounted } from "vue";
|
|
941
|
+
import { CollectionPicker } from "@umbra-ui/core";
|
|
942
|
+
import type { CollectionItem } from "@umbra-ui/core";
|
|
943
|
+
|
|
944
|
+
const items = ref<CollectionItem[]>([]);
|
|
945
|
+
const selectedItem = ref<CollectionItem | null>(null);
|
|
946
|
+
const loading = ref(false);
|
|
947
|
+
|
|
948
|
+
// Simulate API calls
|
|
949
|
+
const fetchItems = async () => {
|
|
950
|
+
loading.value = true;
|
|
951
|
+
try {
|
|
952
|
+
// Simulate API call
|
|
953
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
954
|
+
items.value = [
|
|
955
|
+
{ id: "1", title: "API Item 1" },
|
|
956
|
+
{ id: "2", title: "API Item 2" },
|
|
957
|
+
{ id: "3", title: "API Item 3" },
|
|
958
|
+
];
|
|
959
|
+
} catch (error) {
|
|
960
|
+
console.error("Failed to fetch items:", error);
|
|
961
|
+
} finally {
|
|
962
|
+
loading.value = false;
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
|
|
966
|
+
const createItem = async (title: string) => {
|
|
967
|
+
try {
|
|
968
|
+
// Simulate API call
|
|
969
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
970
|
+
const newItem: CollectionItem = {
|
|
971
|
+
id: Date.now().toString(),
|
|
972
|
+
title: title,
|
|
973
|
+
};
|
|
974
|
+
items.value.push(newItem);
|
|
975
|
+
selectedItem.value = newItem;
|
|
976
|
+
return newItem;
|
|
977
|
+
} catch (error) {
|
|
978
|
+
console.error("Failed to create item:", error);
|
|
979
|
+
throw error;
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
|
|
983
|
+
const handleItemSelected = (item: CollectionItem) => {
|
|
984
|
+
console.log("Selected item:", item);
|
|
985
|
+
};
|
|
986
|
+
|
|
987
|
+
const handleItemCreate = async (title: string) => {
|
|
988
|
+
try {
|
|
989
|
+
await createItem(title);
|
|
990
|
+
console.log("Item created successfully");
|
|
991
|
+
} catch (error) {
|
|
992
|
+
console.error("Failed to create item");
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
|
|
996
|
+
onMounted(() => {
|
|
997
|
+
fetchItems();
|
|
998
|
+
});
|
|
999
|
+
</script>
|
|
1000
|
+
|
|
1001
|
+
<template>
|
|
1002
|
+
<div class="api-integration">
|
|
1003
|
+
<h3>API Integration Example</h3>
|
|
1004
|
+
|
|
1005
|
+
<CollectionPicker
|
|
1006
|
+
v-model:selected-item="selectedItem"
|
|
1007
|
+
:items="items"
|
|
1008
|
+
:loading="loading"
|
|
1009
|
+
button-label="Select Item"
|
|
1010
|
+
header-label="Choose an Item"
|
|
1011
|
+
new-item-label="Create New Item"
|
|
1012
|
+
@item-selected="handleItemSelected"
|
|
1013
|
+
@item-create="handleItemCreate"
|
|
1014
|
+
/>
|
|
1015
|
+
|
|
1016
|
+
<div class="actions">
|
|
1017
|
+
<button @click="fetchItems" :disabled="loading" class="refresh-btn">
|
|
1018
|
+
{{ loading ? "Loading..." : "Refresh Items" }}
|
|
1019
|
+
</button>
|
|
1020
|
+
</div>
|
|
1021
|
+
</div>
|
|
1022
|
+
</template>
|
|
1023
|
+
|
|
1024
|
+
<style module>
|
|
1025
|
+
.api-integration {
|
|
1026
|
+
padding: 24px;
|
|
1027
|
+
max-width: 400px;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
.actions {
|
|
1031
|
+
margin-top: 16px;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
.refresh-btn {
|
|
1035
|
+
padding: 8px 16px;
|
|
1036
|
+
background: #007bff;
|
|
1037
|
+
color: white;
|
|
1038
|
+
border: none;
|
|
1039
|
+
border-radius: 6px;
|
|
1040
|
+
cursor: pointer;
|
|
1041
|
+
transition: background 0.2s ease;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
.refresh-btn:hover:not(:disabled) {
|
|
1045
|
+
background: #0056b3;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
.refresh-btn:disabled {
|
|
1049
|
+
opacity: 0.6;
|
|
1050
|
+
cursor: not-allowed;
|
|
1051
|
+
}
|
|
1052
|
+
</style>
|
|
1053
|
+
```
|
|
1054
|
+
|
|
1055
|
+
## Performance Considerations
|
|
1056
|
+
|
|
1057
|
+
- **Floating UI**: Smart positioning with automatic updates and cleanup
|
|
1058
|
+
- **Teleport**: Overlay and picker are teleported to body for proper z-index management
|
|
1059
|
+
- **Event Cleanup**: Proper cleanup of auto-update listeners on unmount
|
|
1060
|
+
- **Icon Loading**: Icons are loaded on-demand from the @umbra-ui/icons package
|
|
1061
|
+
|
|
1062
|
+
## Accessibility
|
|
1063
|
+
|
|
1064
|
+
- **Keyboard Navigation**: Support for Enter and Escape keys in input
|
|
1065
|
+
- **Screen Reader Support**: Proper ARIA labels and semantic structure
|
|
1066
|
+
- **Focus Management**: Focus is properly managed during interactions
|
|
1067
|
+
- **Overlay Interaction**: Click outside to close functionality
|
|
1068
|
+
|
|
1069
|
+
## Browser Support
|
|
1070
|
+
|
|
1071
|
+
- **Modern Browsers**: Chrome 88+, Firefox 85+, Safari 14+, Edge 88+
|
|
1072
|
+
- **Mobile Browsers**: iOS Safari 14+, Chrome Mobile 88+
|
|
1073
|
+
- **CSS Features**: Uses CSS Grid and modern layout features
|
|
1074
|
+
- **JavaScript**: Requires ES2020+ support
|
|
1075
|
+
|
|
1076
|
+
## Troubleshooting
|
|
1077
|
+
|
|
1078
|
+
### Common Issues
|
|
1079
|
+
|
|
1080
|
+
1. **Picker not positioning correctly**: Ensure the trigger button has proper positioning context
|
|
1081
|
+
2. **Items not displaying**: Check that the items array is properly formatted with id and title
|
|
1082
|
+
3. **Icons not showing**: Verify icon names match those available in @umbra-ui/icons
|
|
1083
|
+
4. **Overlay not closing**: Ensure the overlay click handler is properly bound
|
|
1084
|
+
|
|
1085
|
+
### Debug Mode
|
|
1086
|
+
|
|
1087
|
+
```vue
|
|
1088
|
+
<script setup lang="ts">
|
|
1089
|
+
import { ref, watch } from "vue";
|
|
1090
|
+
import { CollectionPicker } from "@umbra-ui/core";
|
|
1091
|
+
|
|
1092
|
+
const selectedItem = ref(null);
|
|
1093
|
+
|
|
1094
|
+
// Watch for changes
|
|
1095
|
+
watch(selectedItem, (newItem) => {
|
|
1096
|
+
console.log("Selected item changed:", newItem);
|
|
1097
|
+
});
|
|
1098
|
+
</script>
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
## Migration Guide
|
|
1102
|
+
|
|
1103
|
+
### From v1 to v2
|
|
1104
|
+
|
|
1105
|
+
- `v-model` prop is now `v-model:selected-item`
|
|
1106
|
+
- Event names have been updated to use kebab-case
|
|
1107
|
+
- Icon system has been updated to use @umbra-ui/icons
|
|
1108
|
+
- Floating UI integration has been improved
|
|
1109
|
+
|
|
1110
|
+
### Breaking Changes
|
|
1111
|
+
|
|
1112
|
+
- Removed `value` prop in favor of `v-model:selected-item`
|
|
1113
|
+
- Changed event names from camelCase to kebab-case
|
|
1114
|
+
- Updated icon prop to use string names instead of components
|
|
1115
|
+
- Modified CSS class naming convention
|