@skewedaspect/sleekspace-ui 0.5.1 → 0.6.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/Card/SkCard.vue.d.ts +13 -1
- package/dist/components/Panel/SkPanel.vue.d.ts +15 -1
- package/dist/components/Panel/types.d.ts +1 -0
- package/dist/components/Select/SkSelect.vue.d.ts +61 -0
- package/dist/components/Select/SkSelectItem.vue.d.ts +134 -0
- package/dist/components/Select/SkSelectSeparator.vue.d.ts +2 -0
- package/dist/components/Select/index.d.ts +4 -0
- package/dist/components/Select/types.d.ts +3 -0
- package/dist/components/Sidebar/SkSidebar.vue.d.ts +8 -1
- package/dist/components/Sidebar/types.d.ts +1 -0
- package/dist/components/Skeleton/SkSkeleton.vue.d.ts +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/sleekspace-ui.css +444 -34
- package/dist/sleekspace-ui.es.js +2014 -283
- package/dist/sleekspace-ui.umd.js +2013 -282
- package/package.json +1 -1
- package/src/components/Card/SkCard.vue +17 -1
- package/src/components/Panel/SkPanel.vue +29 -4
- package/src/components/Panel/types.ts +3 -0
- package/src/components/Select/SkSelect.vue +210 -0
- package/src/components/Select/SkSelectItem.vue +112 -0
- package/src/components/Select/SkSelectSeparator.vue +40 -0
- package/src/components/Select/index.ts +10 -0
- package/src/components/Select/types.ts +10 -0
- package/src/components/Sidebar/SkSidebar.vue +39 -2
- package/src/components/Sidebar/types.ts +2 -0
- package/src/global.d.ts +2 -0
- package/src/index.ts +10 -0
- package/src/styles/components/_card.scss +45 -9
- package/src/styles/components/_index.scss +1 -0
- package/src/styles/components/_listbox.scss +1 -0
- package/src/styles/components/_panel.scss +119 -13
- package/src/styles/components/_select.scss +439 -0
- package/src/styles/components/_sidebar.scss +83 -4
- package/web-types.json +148 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skewedaspect/sleekspace-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "A Vue 3 component library with a cyberpunk aesthetic, featuring OKLCH colors, beveled corners, and a powerful design token system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/sleekspace-ui.umd.js",
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
:no-border="noBorder"
|
|
11
11
|
:base-color="baseColor"
|
|
12
12
|
:text-color="textColor"
|
|
13
|
+
:corners="corners"
|
|
14
|
+
:decoration-corner="decorationCorner"
|
|
13
15
|
:class="classes"
|
|
14
16
|
>
|
|
15
17
|
<div v-if="title || $slots.header" class="sk-card-header" :style="headerStyles">
|
|
@@ -66,7 +68,7 @@
|
|
|
66
68
|
// Types
|
|
67
69
|
import type { ComponentCustomColors } from '@/types';
|
|
68
70
|
import type { SkCardKind } from './types';
|
|
69
|
-
import type { SkPanelSize } from '../Panel/types';
|
|
71
|
+
import type { SkPanelCorner, SkPanelSize } from '../Panel/types';
|
|
70
72
|
|
|
71
73
|
// Components
|
|
72
74
|
import SkPanel from '../Panel/SkPanel.vue';
|
|
@@ -136,6 +138,18 @@
|
|
|
136
138
|
* @default false
|
|
137
139
|
*/
|
|
138
140
|
scrollable ?: boolean;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Which corners receive the beveled cut. Passed through to the underlying SkPanel.
|
|
144
|
+
* @default ['bottom-right']
|
|
145
|
+
*/
|
|
146
|
+
corners ?: SkPanelCorner[];
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Which corner displays the decorative accent stripe. Passed through to SkPanel.
|
|
150
|
+
* @default 'bottom-right'
|
|
151
|
+
*/
|
|
152
|
+
decorationCorner ?: SkPanelCorner;
|
|
139
153
|
}
|
|
140
154
|
|
|
141
155
|
//------------------------------------------------------------------------------------------------------------------
|
|
@@ -149,6 +163,8 @@
|
|
|
149
163
|
title: undefined,
|
|
150
164
|
headerColor: undefined,
|
|
151
165
|
scrollable: false,
|
|
166
|
+
corners: () => [ 'bottom-right' ],
|
|
167
|
+
decorationCorner: 'bottom-right',
|
|
152
168
|
});
|
|
153
169
|
|
|
154
170
|
//------------------------------------------------------------------------------------------------------------------
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
|
|
41
41
|
// Types
|
|
42
42
|
import type { ComponentCustomColors } from '@/types';
|
|
43
|
-
import type { SkPanelKind, SkPanelSize } from './types';
|
|
43
|
+
import type { SkPanelCorner, SkPanelKind, SkPanelSize } from './types';
|
|
44
44
|
|
|
45
45
|
// Composables
|
|
46
46
|
import { useCustomColors } from '@/composables/useCustomColors';
|
|
@@ -81,6 +81,20 @@
|
|
|
81
81
|
* @default false
|
|
82
82
|
*/
|
|
83
83
|
noBorder ?: boolean;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Which corners receive the beveled cut. Any combination of the four corners can be
|
|
87
|
+
* specified. Pass an empty array for no cut corners.
|
|
88
|
+
* @default ['bottom-right']
|
|
89
|
+
*/
|
|
90
|
+
corners ?: SkPanelCorner[];
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Which corner displays the decorative accent stripe. Must be one of the active
|
|
94
|
+
* `corners` for the decoration to be visible.
|
|
95
|
+
* @default 'bottom-right'
|
|
96
|
+
*/
|
|
97
|
+
decorationCorner ?: SkPanelCorner;
|
|
84
98
|
}
|
|
85
99
|
|
|
86
100
|
//------------------------------------------------------------------------------------------------------------------
|
|
@@ -90,6 +104,8 @@
|
|
|
90
104
|
size: 'md',
|
|
91
105
|
showDecoration: true,
|
|
92
106
|
noBorder: false,
|
|
107
|
+
corners: () => [ 'bottom-right' ],
|
|
108
|
+
decorationCorner: 'bottom-right',
|
|
93
109
|
});
|
|
94
110
|
|
|
95
111
|
//------------------------------------------------------------------------------------------------------------------
|
|
@@ -101,6 +117,11 @@
|
|
|
101
117
|
[`sk-${ props.kind }`]: true,
|
|
102
118
|
[`sk-${ props.size }`]: true,
|
|
103
119
|
'sk-no-border': props.noBorder,
|
|
120
|
+
'sk-cut-top-left': props.corners.includes('top-left'),
|
|
121
|
+
'sk-cut-top-right': props.corners.includes('top-right'),
|
|
122
|
+
'sk-cut-bottom-right': props.corners.includes('bottom-right'),
|
|
123
|
+
'sk-cut-bottom-left': props.corners.includes('bottom-left'),
|
|
124
|
+
[`sk-decoration-${ props.decorationCorner }`]: true,
|
|
104
125
|
};
|
|
105
126
|
});
|
|
106
127
|
|
|
@@ -116,14 +137,18 @@
|
|
|
116
137
|
//------------------------------------------------------------------------------------------------------------------
|
|
117
138
|
|
|
118
139
|
// Control decoration visibility
|
|
119
|
-
//
|
|
140
|
+
// Hidden when: noBorder, showDecoration is false, or decorationCorner isn't in corners
|
|
120
141
|
const decorationDisplay = computed(() =>
|
|
121
142
|
{
|
|
122
|
-
if(props.noBorder)
|
|
143
|
+
if(props.noBorder || !props.showDecoration)
|
|
144
|
+
{
|
|
145
|
+
return 'none';
|
|
146
|
+
}
|
|
147
|
+
if(!props.corners.includes(props.decorationCorner))
|
|
123
148
|
{
|
|
124
149
|
return 'none';
|
|
125
150
|
}
|
|
126
|
-
return
|
|
151
|
+
return 'block';
|
|
127
152
|
});
|
|
128
153
|
</script>
|
|
129
154
|
|
|
@@ -12,4 +12,7 @@ export type SkPanelKind = ComponentKind;
|
|
|
12
12
|
// Panel sizes (only affects cut size, not padding or dimensions)
|
|
13
13
|
export type SkPanelSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
14
14
|
|
|
15
|
+
// Which corners get the bevel cut
|
|
16
|
+
export type SkPanelCorner = 'top-left' | 'top-right' | 'bottom-right' | 'bottom-left';
|
|
17
|
+
|
|
15
18
|
//----------------------------------------------------------------------------------------------------------------------
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
<!----------------------------------------------------------------------------------------------------------------------
|
|
2
|
+
- Select Component
|
|
3
|
+
--------------------------------------------------------------------------------------------------------------------->
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<div :class="wrapperClasses" :style="customColorStyles">
|
|
7
|
+
<SelectRoot v-model="modelValue" :disabled="disabled">
|
|
8
|
+
<SelectTrigger :class="triggerClasses">
|
|
9
|
+
<SelectValue :placeholder="placeholder">
|
|
10
|
+
<template v-if="displayText">
|
|
11
|
+
{{ displayText }}
|
|
12
|
+
</template>
|
|
13
|
+
</SelectValue>
|
|
14
|
+
<svg
|
|
15
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
16
|
+
viewBox="0 0 24 24"
|
|
17
|
+
fill="none"
|
|
18
|
+
stroke="currentColor"
|
|
19
|
+
stroke-width="2"
|
|
20
|
+
stroke-linecap="square"
|
|
21
|
+
stroke-linejoin="miter"
|
|
22
|
+
style="width: 1rem; height: 1rem; flex-shrink: 0;"
|
|
23
|
+
>
|
|
24
|
+
<polyline points="6 9 12 15 18 9" />
|
|
25
|
+
</svg>
|
|
26
|
+
</SelectTrigger>
|
|
27
|
+
|
|
28
|
+
<SelectPortal>
|
|
29
|
+
<SelectContent
|
|
30
|
+
:data-scheme="theme"
|
|
31
|
+
:class="contentClasses"
|
|
32
|
+
:style="customColorStyles"
|
|
33
|
+
position="popper"
|
|
34
|
+
side="bottom"
|
|
35
|
+
align="start"
|
|
36
|
+
:side-offset="4"
|
|
37
|
+
>
|
|
38
|
+
<SelectViewport>
|
|
39
|
+
<slot />
|
|
40
|
+
</SelectViewport>
|
|
41
|
+
</SelectContent>
|
|
42
|
+
</SelectPortal>
|
|
43
|
+
</SelectRoot>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
48
|
+
|
|
49
|
+
<style lang="scss" scoped>
|
|
50
|
+
// Component styles are in /src/styles/components/_select.scss
|
|
51
|
+
</style>
|
|
52
|
+
|
|
53
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
54
|
+
|
|
55
|
+
<script setup lang="ts">
|
|
56
|
+
/**
|
|
57
|
+
* @component SkSelect
|
|
58
|
+
* @description A simple dropdown select for picking from predefined options. Unlike SkListbox which includes
|
|
59
|
+
* a search input for filtering, SkSelect provides a clean trigger button that opens a dropdown panel.
|
|
60
|
+
* Built on RekaUI's Select primitive with full keyboard navigation and portal rendering.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```vue
|
|
64
|
+
* <SkSelect v-model="selectedCountry" kind="primary" placeholder="Select a country...">
|
|
65
|
+
* <SkSelectItem value="us">United States</SkSelectItem>
|
|
66
|
+
* <SkSelectItem value="uk">United Kingdom</SkSelectItem>
|
|
67
|
+
* <SkSelectItem value="ca">Canada</SkSelectItem>
|
|
68
|
+
* </SkSelect>
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @slot default - SkSelectItem components representing the available options. Use SkSelectSeparator
|
|
72
|
+
* to create visual dividers between groups of options.
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
import { type ComputedRef, computed, inject, provide, reactive, toRef } from 'vue';
|
|
76
|
+
import {
|
|
77
|
+
SelectContent,
|
|
78
|
+
SelectPortal,
|
|
79
|
+
SelectRoot,
|
|
80
|
+
SelectTrigger,
|
|
81
|
+
SelectValue,
|
|
82
|
+
SelectViewport,
|
|
83
|
+
} from 'reka-ui';
|
|
84
|
+
|
|
85
|
+
// Types
|
|
86
|
+
import type { ComponentCustomColors } from '@/types';
|
|
87
|
+
import type { SkSelectKind, SkSelectSize } from './types';
|
|
88
|
+
|
|
89
|
+
// Composables
|
|
90
|
+
import { useCustomColors } from '@/composables/useCustomColors';
|
|
91
|
+
import { usePortalContext } from '@/composables/usePortalContext';
|
|
92
|
+
|
|
93
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
export interface SkSelectComponentProps extends ComponentCustomColors
|
|
96
|
+
{
|
|
97
|
+
/**
|
|
98
|
+
* Semantic color kind that controls the trigger border, focus ring, and selected
|
|
99
|
+
* item highlight appearance. When used inside SkField, inherits the field's
|
|
100
|
+
* kind if not explicitly set.
|
|
101
|
+
* @default 'neutral' (or inherited from parent SkField)
|
|
102
|
+
*/
|
|
103
|
+
kind ?: SkSelectKind;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Size of the trigger and dropdown content. Controls the trigger height,
|
|
107
|
+
* text size, and option item dimensions. Available sizes: 'sm' (small),
|
|
108
|
+
* 'md' (medium), 'lg' (large).
|
|
109
|
+
* @default 'md'
|
|
110
|
+
*/
|
|
111
|
+
size ?: SkSelectSize;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Placeholder text displayed in the trigger when no option is selected.
|
|
115
|
+
* Use to guide users on what type of selection to make.
|
|
116
|
+
* @default 'Select...'
|
|
117
|
+
*/
|
|
118
|
+
placeholder ?: string;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* When true, the select is disabled and cannot be interacted with. The trigger
|
|
122
|
+
* is non-clickable and the dropdown cannot be opened. The component appears
|
|
123
|
+
* with reduced opacity and the cursor changes to not-allowed.
|
|
124
|
+
* @default false
|
|
125
|
+
*/
|
|
126
|
+
disabled ?: boolean;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
const props = withDefaults(defineProps<SkSelectComponentProps>(), {
|
|
132
|
+
kind: undefined,
|
|
133
|
+
size: 'md',
|
|
134
|
+
placeholder: 'Select...',
|
|
135
|
+
disabled: false,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The selected value. Use with `v-model` for two-way binding. The value corresponds
|
|
142
|
+
* to the `value` prop of the selected SkSelectItem.
|
|
143
|
+
*/
|
|
144
|
+
const modelValue = defineModel<string>();
|
|
145
|
+
|
|
146
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
147
|
+
|
|
148
|
+
// Handle portal context (theme injection/re-provision for nested portal components)
|
|
149
|
+
const { theme } = usePortalContext();
|
|
150
|
+
|
|
151
|
+
// Inject field kind from parent SkField
|
|
152
|
+
const fieldKind = inject<ComputedRef<SkSelectKind | undefined>>('field-kind', computed(() => undefined));
|
|
153
|
+
|
|
154
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
// Item label registry -- items register their value→label on mount so we can display
|
|
157
|
+
// the selected text synchronously, avoiding the flash from SelectValue's async detection.
|
|
158
|
+
const itemLabels = reactive(new Map<string, string>());
|
|
159
|
+
|
|
160
|
+
provide('sk-select-register', (value : string, label : string) =>
|
|
161
|
+
{
|
|
162
|
+
itemLabels.set(value, label);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
provide('sk-select-unregister', (value : string) =>
|
|
166
|
+
{
|
|
167
|
+
itemLabels.delete(value);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const displayText = computed(() =>
|
|
171
|
+
{
|
|
172
|
+
if(!modelValue.value) { return ''; }
|
|
173
|
+
return itemLabels.get(modelValue.value) || modelValue.value;
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
const effectiveKind = computed(() => fieldKind.value || props.kind || 'neutral');
|
|
179
|
+
|
|
180
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
const wrapperClasses = computed(() => ({
|
|
183
|
+
'sk-select': true,
|
|
184
|
+
[`sk-${ effectiveKind.value }`]: true,
|
|
185
|
+
[`sk-${ props.size }`]: true,
|
|
186
|
+
}));
|
|
187
|
+
|
|
188
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
const triggerClasses = computed(() => ({
|
|
191
|
+
'sk-select-trigger': true,
|
|
192
|
+
}));
|
|
193
|
+
|
|
194
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
195
|
+
|
|
196
|
+
const contentClasses = computed(() => ({
|
|
197
|
+
'sk-select-content': true,
|
|
198
|
+
[`sk-${ effectiveKind.value }`]: true,
|
|
199
|
+
}));
|
|
200
|
+
|
|
201
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
202
|
+
|
|
203
|
+
const customColorStyles = useCustomColors(
|
|
204
|
+
'select',
|
|
205
|
+
toRef(() => props.baseColor),
|
|
206
|
+
toRef(() => props.textColor)
|
|
207
|
+
);
|
|
208
|
+
</script>
|
|
209
|
+
|
|
210
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<!----------------------------------------------------------------------------------------------------------------------
|
|
2
|
+
- SelectItem Component
|
|
3
|
+
--------------------------------------------------------------------------------------------------------------------->
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<SelectItem :class="classes" :value="value" :disabled="disabled">
|
|
7
|
+
<SelectItemText ref="textEl">
|
|
8
|
+
<slot />
|
|
9
|
+
</SelectItemText>
|
|
10
|
+
<SelectItemIndicator class="sk-select-item-indicator">
|
|
11
|
+
<svg
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
viewBox="0 0 24 24"
|
|
14
|
+
fill="none"
|
|
15
|
+
stroke="currentColor"
|
|
16
|
+
stroke-width="3"
|
|
17
|
+
stroke-linecap="square"
|
|
18
|
+
stroke-linejoin="miter"
|
|
19
|
+
style="width: 1rem; height: 1rem;"
|
|
20
|
+
>
|
|
21
|
+
<polyline points="20 6 9 17 4 12" />
|
|
22
|
+
</svg>
|
|
23
|
+
</SelectItemIndicator>
|
|
24
|
+
</SelectItem>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
28
|
+
|
|
29
|
+
<style lang="scss" scoped>
|
|
30
|
+
// Component styles are in /src/styles/components/_select.scss
|
|
31
|
+
</style>
|
|
32
|
+
|
|
33
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
34
|
+
|
|
35
|
+
<script setup lang="ts">
|
|
36
|
+
/**
|
|
37
|
+
* @component SkSelectItem
|
|
38
|
+
* @description A selectable option within an SkSelect dropdown. When selected, the item displays a
|
|
39
|
+
* checkmark indicator and its value is set as the select's v-model. Built on RekaUI's SelectItem
|
|
40
|
+
* with keyboard navigation support.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```vue
|
|
44
|
+
* <SkSelect v-model="selected">
|
|
45
|
+
* <SkSelectItem value="option1">First Option</SkSelectItem>
|
|
46
|
+
* <SkSelectItem value="option2">Second Option</SkSelectItem>
|
|
47
|
+
* <SkSelectItem value="option3" disabled>Unavailable Option</SkSelectItem>
|
|
48
|
+
* </SkSelect>
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @slot default - The display content for this option. Can be plain text or rich content including
|
|
52
|
+
* icons, formatted text, or custom layouts. This is what users see in the dropdown.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
import { computed, inject, onMounted, onUnmounted, useTemplateRef } from 'vue';
|
|
56
|
+
import { SelectItem, SelectItemIndicator, SelectItemText } from 'reka-ui';
|
|
57
|
+
|
|
58
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
59
|
+
|
|
60
|
+
export interface SkSelectItemComponentProps
|
|
61
|
+
{
|
|
62
|
+
/**
|
|
63
|
+
* The value this option represents. When selected, the parent SkSelect's v-model
|
|
64
|
+
* will be set to this value. Must be a string and unique within the select.
|
|
65
|
+
*/
|
|
66
|
+
value : string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* When true, this option is disabled and cannot be selected. The item appears
|
|
70
|
+
* with reduced opacity and is skipped during keyboard navigation.
|
|
71
|
+
* @default false
|
|
72
|
+
*/
|
|
73
|
+
disabled ?: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
const props = withDefaults(defineProps<SkSelectItemComponentProps>(), {
|
|
79
|
+
disabled: false,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
const textEl = useTemplateRef<InstanceType<typeof SelectItemText>>('textEl');
|
|
85
|
+
const register = inject<(value : string, label : string) => void>('sk-select-register', undefined);
|
|
86
|
+
const unregister = inject<(value : string) => void>('sk-select-unregister', undefined);
|
|
87
|
+
|
|
88
|
+
onMounted(() =>
|
|
89
|
+
{
|
|
90
|
+
const el = (textEl.value as unknown as { $el ?: HTMLElement })?.$el;
|
|
91
|
+
if(register)
|
|
92
|
+
{
|
|
93
|
+
register(props.value, el?.textContent?.trim() || props.value);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
onUnmounted(() =>
|
|
98
|
+
{
|
|
99
|
+
if(unregister)
|
|
100
|
+
{
|
|
101
|
+
unregister(props.value);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
const classes = computed(() => ({
|
|
108
|
+
'sk-select-item': true,
|
|
109
|
+
}));
|
|
110
|
+
</script>
|
|
111
|
+
|
|
112
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!----------------------------------------------------------------------------------------------------------------------
|
|
2
|
+
- SelectSeparator Component
|
|
3
|
+
--------------------------------------------------------------------------------------------------------------------->
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<SelectSeparator class="sk-select-separator" />
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
10
|
+
|
|
11
|
+
<style lang="scss" scoped>
|
|
12
|
+
// Component styles are in /src/styles/components/_select.scss
|
|
13
|
+
</style>
|
|
14
|
+
|
|
15
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
16
|
+
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
/**
|
|
19
|
+
* @component SkSelectSeparator
|
|
20
|
+
* @description A visual divider for organizing options within an SkSelect dropdown. Use to create
|
|
21
|
+
* logical groups of related options without affecting selection behavior. Renders as a horizontal
|
|
22
|
+
* line between items with appropriate spacing.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```vue
|
|
26
|
+
* <SkSelect v-model="selected">
|
|
27
|
+
* <SkSelectItem value="recent1">Recent Document 1</SkSelectItem>
|
|
28
|
+
* <SkSelectItem value="recent2">Recent Document 2</SkSelectItem>
|
|
29
|
+
* <SkSelectSeparator />
|
|
30
|
+
* <SkSelectItem value="all">Browse All Documents...</SkSelectItem>
|
|
31
|
+
* </SkSelect>
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @slot - Not applicable. This component does not accept slot content.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import { SelectSeparator } from 'reka-ui';
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<!--------------------------------------------------------------------------------------------------------------------->
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
2
|
+
// Select Component Exports
|
|
3
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
export { default as SkSelect } from './SkSelect.vue';
|
|
6
|
+
export { default as SkSelectItem } from './SkSelectItem.vue';
|
|
7
|
+
export { default as SkSelectSeparator } from './SkSelectSeparator.vue';
|
|
8
|
+
export type { SkSelectKind, SkSelectSize } from './types';
|
|
9
|
+
|
|
10
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
2
|
+
// Select Component Types
|
|
3
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
import type { ComponentKind, ComponentSize } from '@/types';
|
|
6
|
+
|
|
7
|
+
export type SkSelectKind = ComponentKind;
|
|
8
|
+
export type SkSelectSize = ComponentSize;
|
|
9
|
+
|
|
10
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
--------------------------------------------------------------------------------------------------------------------->
|
|
4
4
|
|
|
5
5
|
<template>
|
|
6
|
-
<aside :class="classes">
|
|
6
|
+
<aside :class="classes" :style="sidebarStyles">
|
|
7
7
|
<SkPanel
|
|
8
8
|
:kind="kind"
|
|
9
9
|
:base-color="baseColor"
|
|
10
10
|
:text-color="textColor"
|
|
11
|
+
:corners="panelCorners"
|
|
12
|
+
:decoration-corner="panelDecorationCorner"
|
|
11
13
|
class="sk-sidebar-panel"
|
|
12
14
|
>
|
|
13
15
|
<div class="sk-panel-scroll-content">
|
|
@@ -49,8 +51,13 @@
|
|
|
49
51
|
*/
|
|
50
52
|
|
|
51
53
|
import { computed } from 'vue';
|
|
52
|
-
|
|
54
|
+
|
|
55
|
+
// Types
|
|
56
|
+
import type { SkSidebarKind, SkSidebarSide } from './types';
|
|
53
57
|
import type { ComponentCustomColors } from '@/types';
|
|
58
|
+
import type { SkPanelCorner } from '../Panel/types';
|
|
59
|
+
|
|
60
|
+
// Components
|
|
54
61
|
import SkPanel from '../Panel/SkPanel.vue';
|
|
55
62
|
|
|
56
63
|
//------------------------------------------------------------------------------------------------------------------
|
|
@@ -72,6 +79,13 @@
|
|
|
72
79
|
* @default '180px'
|
|
73
80
|
*/
|
|
74
81
|
width ?: string;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Which side of the layout the sidebar is placed on. Controls the direction of the
|
|
85
|
+
* panel bevel and the sidebar-item clip-path cuts so they mirror appropriately.
|
|
86
|
+
* @default 'left'
|
|
87
|
+
*/
|
|
88
|
+
side ?: SkSidebarSide;
|
|
75
89
|
}
|
|
76
90
|
|
|
77
91
|
//------------------------------------------------------------------------------------------------------------------
|
|
@@ -79,17 +93,40 @@
|
|
|
79
93
|
const props = withDefaults(defineProps<SkSidebarComponentProps>(), {
|
|
80
94
|
kind: 'neutral',
|
|
81
95
|
width: '180px',
|
|
96
|
+
side: 'left',
|
|
82
97
|
});
|
|
83
98
|
|
|
84
99
|
//------------------------------------------------------------------------------------------------------------------
|
|
85
100
|
|
|
101
|
+
const panelCorners = computed<SkPanelCorner[]>(() =>
|
|
102
|
+
{
|
|
103
|
+
return props.side === 'right' ? [ 'bottom-left' ] : [ 'bottom-right' ];
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const panelDecorationCorner = computed<SkPanelCorner>(() =>
|
|
107
|
+
{
|
|
108
|
+
return props.side === 'right' ? 'bottom-left' : 'bottom-right';
|
|
109
|
+
});
|
|
110
|
+
|
|
86
111
|
const classes = computed(() =>
|
|
87
112
|
{
|
|
88
113
|
return {
|
|
89
114
|
'sk-sidebar': true,
|
|
90
115
|
[`sk-${ props.kind }`]: true,
|
|
116
|
+
'sk-sidebar-right': props.side === 'right',
|
|
91
117
|
};
|
|
92
118
|
});
|
|
119
|
+
|
|
120
|
+
// Bridge custom colors to sidebar item theming
|
|
121
|
+
const sidebarStyles = computed(() =>
|
|
122
|
+
{
|
|
123
|
+
const styles : Record<string, string> = {};
|
|
124
|
+
if(props.baseColor)
|
|
125
|
+
{
|
|
126
|
+
styles['--sk-sidebar-color-base'] = props.baseColor;
|
|
127
|
+
}
|
|
128
|
+
return styles;
|
|
129
|
+
});
|
|
93
130
|
</script>
|
|
94
131
|
|
|
95
132
|
<!--------------------------------------------------------------------------------------------------------------------->
|
package/src/global.d.ts
CHANGED
|
@@ -49,6 +49,8 @@ declare module '@vue/runtime-core' {
|
|
|
49
49
|
SkProgress: DefineComponent<import('./components/Progress/SkProgress.vue').SkProgressComponentProps>;
|
|
50
50
|
SkRadio: DefineComponent<import('./components/Radio/SkRadio.vue').SkRadioComponentProps>;
|
|
51
51
|
SkRadioGroup: DefineComponent<import('./components/Radio/SkRadioGroup.vue').SkRadioGroupComponentProps>;
|
|
52
|
+
SkSelect: DefineComponent<import('./components/Select/SkSelect.vue').SkSelectComponentProps>;
|
|
53
|
+
SkSelectItem: DefineComponent<import('./components/Select/SkSelectItem.vue').SkSelectItemComponentProps>;
|
|
52
54
|
SkSidebar: DefineComponent<import('./components/Sidebar/SkSidebar.vue').SkSidebarComponentProps>;
|
|
53
55
|
SkSidebarItem: DefineComponent<import('./components/Sidebar/SkSidebarItem.vue').SkSidebarItemComponentProps>;
|
|
54
56
|
SkSidebarSection: DefineComponent<import('./components/Sidebar/SkSidebarSection.vue').SkSidebarSectionComponentProps>;
|
package/src/index.ts
CHANGED
|
@@ -50,6 +50,9 @@ import SkPopover, { type SkPopoverComponentProps } from './components/Popover/Sk
|
|
|
50
50
|
import SkProgress, { type SkProgressComponentProps } from './components/Progress/SkProgress.vue';
|
|
51
51
|
import SkRadio, { type SkRadioComponentProps } from './components/Radio/SkRadio.vue';
|
|
52
52
|
import SkRadioGroup, { type SkRadioGroupComponentProps } from './components/Radio/SkRadioGroup.vue';
|
|
53
|
+
import SkSelect, { type SkSelectComponentProps } from './components/Select/SkSelect.vue';
|
|
54
|
+
import SkSelectItem, { type SkSelectItemComponentProps } from './components/Select/SkSelectItem.vue';
|
|
55
|
+
import SkSelectSeparator from './components/Select/SkSelectSeparator.vue';
|
|
53
56
|
import SkSidebar, { type SkSidebarComponentProps } from './components/Sidebar/SkSidebar.vue';
|
|
54
57
|
import SkSidebarItem, { type SkSidebarItemComponentProps } from './components/Sidebar/SkSidebarItem.vue';
|
|
55
58
|
import SkSidebarSection, { type SkSidebarSectionComponentProps } from './components/Sidebar/SkSidebarSection.vue';
|
|
@@ -108,6 +111,7 @@ export * from './components/Panel/types';
|
|
|
108
111
|
export * from './components/Popover/types';
|
|
109
112
|
export * from './components/Progress/types';
|
|
110
113
|
export * from './components/Radio/types';
|
|
114
|
+
export * from './components/Select/types';
|
|
111
115
|
export * from './components/Sidebar/types';
|
|
112
116
|
export * from './components/Skeleton/types';
|
|
113
117
|
export * from './components/Slider/types';
|
|
@@ -166,6 +170,9 @@ export { SkPopover, type SkPopoverComponentProps };
|
|
|
166
170
|
export { SkProgress, type SkProgressComponentProps };
|
|
167
171
|
export { SkRadio, type SkRadioComponentProps };
|
|
168
172
|
export { SkRadioGroup, type SkRadioGroupComponentProps };
|
|
173
|
+
export { SkSelect, type SkSelectComponentProps };
|
|
174
|
+
export { SkSelectItem, type SkSelectItemComponentProps };
|
|
175
|
+
export { SkSelectSeparator };
|
|
169
176
|
export { SkSidebar, type SkSidebarComponentProps };
|
|
170
177
|
export { SkSidebarItem, type SkSidebarItemComponentProps };
|
|
171
178
|
export { SkSidebarSection, type SkSidebarSectionComponentProps };
|
|
@@ -229,6 +236,9 @@ const SleekSpaceUI : Plugin = {
|
|
|
229
236
|
app.component('SkProgress', SkProgress);
|
|
230
237
|
app.component('SkRadio', SkRadio);
|
|
231
238
|
app.component('SkRadioGroup', SkRadioGroup);
|
|
239
|
+
app.component('SkSelect', SkSelect);
|
|
240
|
+
app.component('SkSelectItem', SkSelectItem);
|
|
241
|
+
app.component('SkSelectSeparator', SkSelectSeparator);
|
|
232
242
|
app.component('SkSidebar', SkSidebar);
|
|
233
243
|
app.component('SkSidebarItem', SkSidebarItem);
|
|
234
244
|
app.component('SkSidebarSection', SkSidebarSection);
|