@aleph-alpha/ui-library 1.14.0 → 1.15.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/config.d.ts +18 -5
- package/config.js +61 -4
- package/dist/system/index.d.ts +41 -53
- package/dist/system/lib.js +981 -988
- package/docs/public-docs/component-directory.md +13 -0
- package/docs/public-docs/contributing.md +11 -0
- package/docs/public-docs/external-links.md +16 -0
- package/docs/public-docs/foundations.md +25 -0
- package/docs/public-docs/getting-started-designers.md +17 -0
- package/docs/public-docs/index.md +5 -0
- package/docs/public-docs/quick-start.md +230 -0
- package/docs/public-docs/standards-guidelines.md +15 -0
- package/package.json +3 -2
- package/src/components/UiCalendar/UiCalendar.stories.ts +1 -4
- package/src/components/UiCalendar/types.ts +1 -1
- package/src/components/UiRangeCalendar/UiRangeCalendar.stories.ts +2 -4
- package/src/components/UiRangeCalendar/types.ts +1 -1
- package/src/components/UiSidebar/UiSidebar.stories.ts +179 -1
- package/src/components/UiSidebar/UiSidebarProvider.vue +1 -3
- package/src/components/UiSidebar/types.ts +6 -9
- package/src/components/core/calendar/Calendar.vue +1 -1
- package/src/components/core/range-calendar/RangeCalendar.vue +1 -1
- package/src/patterns/UiDatePicker/UiDatePicker.stories.ts +1 -4
- package/src/patterns/UiDatePicker/types.ts +1 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Components
|
|
2
|
+
|
|
3
|
+
Explore the design system components: view variants, try them in isolation, and copy code for your app.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Live playground (Storybook)
|
|
8
|
+
|
|
9
|
+
The easiest way to browse and try components and see detailed documentation on each component is Storybook. You can switch props, see states and sizes, see provided examples, etc.
|
|
10
|
+
|
|
11
|
+
**[Open Storybook →](https://dev.aleph-alpha.de/ui-library)**
|
|
12
|
+
|
|
13
|
+
More soon.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# External Links
|
|
2
|
+
|
|
3
|
+
Quick access to Design System resources.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Coming soon
|
|
8
|
+
|
|
9
|
+
This page will provide:
|
|
10
|
+
|
|
11
|
+
| Resource | Description | Link |
|
|
12
|
+
|----------|-------------|------|
|
|
13
|
+
| 📘 **Storybook (Live Code)** | Live code and component playground | [Storybook](https://dev.aleph-alpha.de/ui-library) |
|
|
14
|
+
| 🎨 **Figma (Design System)** | Design system files | [Figma](https://www.figma.com/design/SrZQ19QVN1sQkuAMnMC746/AA26--WIP-?node-id=65-520&m=dev) |
|
|
15
|
+
| 🐙 **GitHub Repository** | Source code and issues | [GitHub](https://github.com/Aleph-Alpha/frontend-hub/tree/main/packages/ui-library) |
|
|
16
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Foundations
|
|
2
|
+
|
|
3
|
+
*Links to Storybook.*
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Color & Dark Mode
|
|
8
|
+
|
|
9
|
+
Coming soon.
|
|
10
|
+
|
|
11
|
+
## Spacing & Grid
|
|
12
|
+
|
|
13
|
+
Coming soon.
|
|
14
|
+
|
|
15
|
+
## Typography
|
|
16
|
+
|
|
17
|
+
Coming soon.
|
|
18
|
+
|
|
19
|
+
## Elevation & Surfaces
|
|
20
|
+
|
|
21
|
+
Coming soon.
|
|
22
|
+
|
|
23
|
+
## Iconography
|
|
24
|
+
|
|
25
|
+
Coming soon.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Getting Started for Designers
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Figma Access & Library Links
|
|
6
|
+
|
|
7
|
+
Figma components and design files:
|
|
8
|
+
|
|
9
|
+
- **[AA Design System Components (Figma)](https://www.figma.com/design/SrZQ19QVN1sQkuAMnMC746/AA26--WIP-?node-id=580-9181&t=2HPn1uKWpFKHnrMR-1)** — component library and design system.
|
|
10
|
+
|
|
11
|
+
## Using Design Tokens in Figma
|
|
12
|
+
|
|
13
|
+
Coming soon.
|
|
14
|
+
|
|
15
|
+
## Link to Contribution Model
|
|
16
|
+
|
|
17
|
+
Coming soon.
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Quick Start
|
|
2
|
+
|
|
3
|
+
Get the UI library integrated into your project in under 5 minutes.
|
|
4
|
+
|
|
5
|
+
**Designers:** For Figma, design tokens, and the contribution model, see [Getting Started for Designers](getting-started-designers.md).
|
|
6
|
+
|
|
7
|
+
!!! note "Prerequisites"
|
|
8
|
+
- **Node.js** (>=20.19.0)
|
|
9
|
+
- **pnpm** or **npm**
|
|
10
|
+
- A **Vite + Vue 3** project
|
|
11
|
+
- **MCP (optional):** An editor that supports MCP (Cursor, VS Code, or Claude Code) if you want AI-assisted component discovery
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
**1. Add the library and peer dependencies**
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pnpm add @aleph-alpha/ui-library
|
|
21
|
+
pnpm add -D unocss @unocss/preset-wind4 @unocss/reset unocss-preset-animations unocss-preset-shadcn
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
<details>
|
|
25
|
+
<summary>Using npm?</summary>
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @aleph-alpha/ui-library
|
|
29
|
+
npm install -D unocss @unocss/preset-wind4 @unocss/reset unocss-preset-animations unocss-preset-shadcn
|
|
30
|
+
```
|
|
31
|
+
</details>
|
|
32
|
+
|
|
33
|
+
!!! warning "Use `@unocss/preset-wind4`, not `preset-wind3`"
|
|
34
|
+
The library requires **preset-wind4**. Using preset-wind3 will break hover states and colors because wind3 injects opacity variables (`/ var(--un-bg-opacity)`) that conflict with the library's oklch token values.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Setup and configuration
|
|
39
|
+
|
|
40
|
+
### 2. UnoCSS config
|
|
41
|
+
|
|
42
|
+
Create or update `uno.config.ts` in your project root:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// uno.config.ts
|
|
46
|
+
import { defineConfig } from 'unocss'
|
|
47
|
+
import {
|
|
48
|
+
getUiLibraryContentConfig,
|
|
49
|
+
presetUiLibraryThemeFromTokens,
|
|
50
|
+
presetUiLibraryUtils,
|
|
51
|
+
} from '@aleph-alpha/ui-library/config'
|
|
52
|
+
import presetWind from '@unocss/preset-wind4'
|
|
53
|
+
import presetAnimations from 'unocss-preset-animations'
|
|
54
|
+
import presetShadcn from 'unocss-preset-shadcn'
|
|
55
|
+
|
|
56
|
+
export default defineConfig({
|
|
57
|
+
...getUiLibraryContentConfig(),
|
|
58
|
+
presets: [
|
|
59
|
+
presetWind(),
|
|
60
|
+
presetAnimations(),
|
|
61
|
+
presetShadcn({ color: 'neutral', darkSelector: 'html.dark' }),
|
|
62
|
+
// Must come AFTER presetShadcn — bundles token CSS vars, colors, and typography
|
|
63
|
+
presetUiLibraryThemeFromTokens(),
|
|
64
|
+
presetUiLibraryUtils(),
|
|
65
|
+
],
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**What each part does:**
|
|
70
|
+
|
|
71
|
+
| Config | Purpose |
|
|
72
|
+
|--------|---------|
|
|
73
|
+
| `getUiLibraryContentConfig()` | Scans `node_modules/@aleph-alpha/ui-library` for class usage so UnoCSS generates the right utilities |
|
|
74
|
+
| `presetWind()` | Tailwind-compatible utility classes (must be **wind4**, not wind3) |
|
|
75
|
+
| `presetAnimations()` | CSS animation utilities for transitions |
|
|
76
|
+
| `presetShadcn()` | Base shadcn CSS variables and color utilities |
|
|
77
|
+
| `presetUiLibraryThemeFromTokens()` | Token preset — must come **after** `presetShadcn`. Bundles design token CSS variables (light/dark), token-based theme colors (`bg-background-surface-secondary`, etc.), semantic color overrides (`background`, `foreground`, `modal`, etc.), and typography classes (`heading-48-bold`, `body-14-normal`, `label-12-medium`, etc.) |
|
|
78
|
+
| `presetUiLibraryUtils()` | Utility rules required by library components — Tailwind v4 CSS variable syntax (`w-(--var)`, `h-(--var)`, etc.) not yet supported by preset-wind4 |
|
|
79
|
+
|
|
80
|
+
### 3. Vite config
|
|
81
|
+
|
|
82
|
+
Ensure your `vite.config.ts` includes both the Vue plugin and the UnoCSS Vite plugin:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// vite.config.ts
|
|
86
|
+
import { defineConfig } from 'vite'
|
|
87
|
+
import vue from '@vitejs/plugin-vue'
|
|
88
|
+
import UnoCSS from 'unocss/vite'
|
|
89
|
+
|
|
90
|
+
export default defineConfig({
|
|
91
|
+
plugins: [vue(), UnoCSS()],
|
|
92
|
+
})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 4. Global styles and app entry
|
|
96
|
+
|
|
97
|
+
In your main entry (e.g. `main.ts`), import the UnoCSS reset and the generated CSS. These imports must run before your app mounts so that component styles apply everywhere.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// main.ts
|
|
101
|
+
import '@unocss/reset/tailwind.css'
|
|
102
|
+
import 'virtual:uno.css'
|
|
103
|
+
|
|
104
|
+
import { createApp } from 'vue'
|
|
105
|
+
import App from './App.vue'
|
|
106
|
+
|
|
107
|
+
createApp(App).mount('#app')
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Test it
|
|
113
|
+
|
|
114
|
+
Use a component to confirm everything works:
|
|
115
|
+
|
|
116
|
+
```vue
|
|
117
|
+
<script setup lang="ts">
|
|
118
|
+
import { UiButton, UiBadge } from '@aleph-alpha/ui-library'
|
|
119
|
+
</script>
|
|
120
|
+
|
|
121
|
+
<template>
|
|
122
|
+
<div class="min-h-screen bg-background text-foreground p-8">
|
|
123
|
+
<UiButton>Click me</UiButton>
|
|
124
|
+
<UiBadge variant="secondary">New</UiBadge>
|
|
125
|
+
</div>
|
|
126
|
+
</template>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Run your dev server (e.g. `pnpm dev`) and open the app. The button and badge should render with the correct styles and colors matching [Storybook](https://dev.aleph-alpha.de/ui-library).
|
|
130
|
+
|
|
131
|
+
**If colors look wrong or hover states don't work:**
|
|
132
|
+
|
|
133
|
+
- Verify you're using `@unocss/preset-wind4` (not wind3) — check your `package.json`
|
|
134
|
+
- Verify `presetUiLibraryThemeFromTokens()` comes **after** `presetShadcn()` in the presets array
|
|
135
|
+
- Clear the Vite cache: `rm -rf node_modules/.vite && pnpm dev`
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Dark mode
|
|
140
|
+
|
|
141
|
+
The library supports dark mode via the `html.dark` class. Toggle it on the document element:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// Toggle dark mode
|
|
145
|
+
document.documentElement.classList.toggle('dark')
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Both `presetShadcn` and `presetUiLibraryThemeFromTokens` default to `darkSelector: 'html.dark'`, so CSS variables switch correctly out of the box.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Config exports reference
|
|
153
|
+
|
|
154
|
+
All config functions are exported from `@aleph-alpha/ui-library/config`:
|
|
155
|
+
|
|
156
|
+
| Export | Description |
|
|
157
|
+
|--------|-------------|
|
|
158
|
+
| `getUiLibraryContentConfig()` | UnoCSS content/pipeline config to scan library classes |
|
|
159
|
+
| `presetUiLibraryThemeFromTokens(options?)` | **Token preset.** Bundles token CSS variables, theme colors, semantic overrides, and typography classes. Options: `darkSelector` (default: `'html.dark'`), `includeAllTokens` (default: `true`), `extend`, `theme` |
|
|
160
|
+
| `presetUiLibraryUtils()` | Utility rules required by library components (`w-(--var)`, `h-(--var)`, etc.) |
|
|
161
|
+
| `presetUiLibraryTheme(theme, options?)` | Low-level preset with manually provided theme variables (for custom themes) |
|
|
162
|
+
| `getUiLibraryThemeFromTokens()` | Returns the raw theme object derived from `tokens.json` |
|
|
163
|
+
| `getUiLibraryTokenVars()` | Returns all token-based CSS variables for light and dark modes |
|
|
164
|
+
| `getUiLibraryTokenColors()` | Returns UnoCSS theme colors config for all token-based colors (included automatically by `presetUiLibraryThemeFromTokens`) |
|
|
165
|
+
| `getUiLibraryTypographyShortcuts()` | Returns typography class definitions as `[className, cssProperties]` tuples (included automatically by `presetUiLibraryThemeFromTokens`) |
|
|
166
|
+
| `defineThemeConfig(config)` | Type-safe helper for external theme config files |
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## MCP Integration
|
|
171
|
+
|
|
172
|
+
Enable AI assistants (Cursor, Claude Code, etc.) to discover and use UI library components.
|
|
173
|
+
|
|
174
|
+
!!! warning "Run from your project directory"
|
|
175
|
+
Run the installer from the **project that uses the UI library** (your app root). It detects the root from the current working directory and writes `.mcp.json` or `.cursor/mcp.json` there. Running it from the wrong folder will use the wrong root or fail.
|
|
176
|
+
|
|
177
|
+
**1. Run the installer**
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npx @aleph-alpha/lib-mcp mcp-install
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**2. For Cursor**: add the Cursor-specific config:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npx @aleph-alpha/lib-mcp mcp-install --cursor
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**3. Restart your editor** so it picks up the MCP server.
|
|
190
|
+
|
|
191
|
+
**Available tools:**
|
|
192
|
+
|
|
193
|
+
| Tool | Description |
|
|
194
|
+
|------|-------------|
|
|
195
|
+
| `list_components` | Browse all components, optionally filter by name/category/description |
|
|
196
|
+
| `get_component_docs` | Get full documentation for a component including props, examples, and usage |
|
|
197
|
+
| `get_setup_guide` | Get this setup guide (so AI assistants can configure projects correctly) |
|
|
198
|
+
|
|
199
|
+
### Or add the server manually
|
|
200
|
+
|
|
201
|
+
If you prefer not to run the installer, add the MCP server yourself.
|
|
202
|
+
|
|
203
|
+
1. **Where to put the config** (see your editor docs):
|
|
204
|
+
|
|
205
|
+
| Editor | Config location / docs |
|
|
206
|
+
|--------|------------------------|
|
|
207
|
+
| **Cursor** | [Using mcp.json](https://cursor.com/docs/context/mcp#using-mcpjson) — use `.cursor/mcp.json` in your project or `~/.cursor/mcp.json` globally |
|
|
208
|
+
| **VS Code** | [Add and manage MCP servers](https://code.visualstudio.com/docs/copilot/customization/mcp-servers#_configure-the-mcpjson-file) — use `.vscode/mcp.json` (workspace) or user config |
|
|
209
|
+
| **Claude Code** | [Add a local stdio server](https://code.claude.com/docs/en/mcp#option-3-add-a-local-stdio-server) — use `.mcp.json` in your project (project scope) |
|
|
210
|
+
|
|
211
|
+
2. **Add this server** to your `mcpServers`:
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"mcpServers": {
|
|
216
|
+
"ui-library": {
|
|
217
|
+
"command": "npx",
|
|
218
|
+
"args": ["-y", "@aleph-alpha/lib-mcp", "serve"]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
3. **Restart your editor** so it picks up the MCP server.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Contribute
|
|
229
|
+
|
|
230
|
+
To contribute to the UI library (guidelines, support, and how to get involved), see [Contributing](contributing.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aleph-alpha/ui-library",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/system/lib.js",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"config.js",
|
|
23
23
|
"config.d.ts",
|
|
24
24
|
"tailwind.preset.js",
|
|
25
|
-
"tokens.json"
|
|
25
|
+
"tokens.json",
|
|
26
|
+
"docs/public-docs"
|
|
26
27
|
],
|
|
27
28
|
"description": "Next-gen UI Library for Vue.js projects.",
|
|
28
29
|
"author": "Aleph Alpha GmbH",
|
|
@@ -31,7 +31,7 @@ const meta: Meta<typeof UiCalendar> = {
|
|
|
31
31
|
weekStartsOn: {
|
|
32
32
|
control: 'select',
|
|
33
33
|
options: [0, 1, 2, 3, 4, 5, 6],
|
|
34
|
-
description: 'The day of the week to start on. 0
|
|
34
|
+
description: 'The day of the week to start on. 0 is the locale default first day.',
|
|
35
35
|
},
|
|
36
36
|
numberOfMonths: {
|
|
37
37
|
control: { type: 'number', min: 1, max: 3 },
|
|
@@ -392,7 +392,6 @@ const date = ref<DateValue>()
|
|
|
392
392
|
<UiCalendar
|
|
393
393
|
v-model="date"
|
|
394
394
|
locale="de"
|
|
395
|
-
:week-starts-on="1"
|
|
396
395
|
weekday-format="short"
|
|
397
396
|
class="rounded-md border shadow-sm"
|
|
398
397
|
/>
|
|
@@ -405,7 +404,6 @@ const date = ref<DateValue>()
|
|
|
405
404
|
export const GermanLocale: Story = {
|
|
406
405
|
args: {
|
|
407
406
|
locale: 'de',
|
|
408
|
-
weekStartsOn: 1,
|
|
409
407
|
weekdayFormat: 'short',
|
|
410
408
|
},
|
|
411
409
|
render: (args) => ({
|
|
@@ -419,7 +417,6 @@ export const GermanLocale: Story = {
|
|
|
419
417
|
v-model="date"
|
|
420
418
|
:default-placeholder="placeholder"
|
|
421
419
|
:locale="args.locale"
|
|
422
|
-
:week-starts-on="args.weekStartsOn"
|
|
423
420
|
:weekday-format="args.weekdayFormat"
|
|
424
421
|
:disabled="args.disabled"
|
|
425
422
|
class="rounded-md border shadow-sm"
|
|
@@ -30,7 +30,7 @@ const meta: Meta<typeof UiRangeCalendar> = {
|
|
|
30
30
|
weekStartsOn: {
|
|
31
31
|
control: 'select',
|
|
32
32
|
options: [0, 1, 2, 3, 4, 5, 6],
|
|
33
|
-
description: 'The day of the week to start on. 0
|
|
33
|
+
description: 'The day of the week to start on. 0 is the locale default first day.',
|
|
34
34
|
},
|
|
35
35
|
numberOfMonths: {
|
|
36
36
|
control: { type: 'number', min: 1, max: 3 },
|
|
@@ -337,7 +337,7 @@ const dateRange = ref<DateRange>()
|
|
|
337
337
|
</script>
|
|
338
338
|
|
|
339
339
|
<template>
|
|
340
|
-
<UiRangeCalendar v-model="dateRange" locale="de"
|
|
340
|
+
<UiRangeCalendar v-model="dateRange" locale="de" weekday-format="short" class="rounded-md border shadow-sm" />
|
|
341
341
|
</template>`;
|
|
342
342
|
|
|
343
343
|
/**
|
|
@@ -347,7 +347,6 @@ const dateRange = ref<DateRange>()
|
|
|
347
347
|
export const GermanLocale: Story = {
|
|
348
348
|
args: {
|
|
349
349
|
locale: 'de',
|
|
350
|
-
weekStartsOn: 1,
|
|
351
350
|
weekdayFormat: 'short',
|
|
352
351
|
},
|
|
353
352
|
render: (args) => ({
|
|
@@ -361,7 +360,6 @@ export const GermanLocale: Story = {
|
|
|
361
360
|
v-model="dateRange"
|
|
362
361
|
:default-placeholder="placeholder"
|
|
363
362
|
:locale="args.locale"
|
|
364
|
-
:week-starts-on="args.weekStartsOn"
|
|
365
363
|
:weekday-format="args.weekdayFormat"
|
|
366
364
|
:disabled="args.disabled"
|
|
367
365
|
class="rounded-md border shadow-sm"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ref, computed } from 'vue';
|
|
1
|
+
import { ref, computed, defineComponent } from 'vue';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
3
3
|
import {
|
|
4
4
|
UiSidebar,
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
UiSidebarRail,
|
|
26
26
|
UiSidebarSeparator,
|
|
27
27
|
UiSidebarTrigger,
|
|
28
|
+
useSidebar,
|
|
28
29
|
} from '.';
|
|
29
30
|
import { CollapsibleRoot, CollapsibleContent, CollapsibleTrigger } from 'reka-ui';
|
|
30
31
|
import {
|
|
@@ -1008,3 +1009,180 @@ export const WithSkeleton: Story = {
|
|
|
1008
1009
|
},
|
|
1009
1010
|
},
|
|
1010
1011
|
};
|
|
1012
|
+
|
|
1013
|
+
const programmaticControlTemplateSource = `<script setup lang="ts">
|
|
1014
|
+
import {
|
|
1015
|
+
UiSidebar,
|
|
1016
|
+
UiSidebarContent,
|
|
1017
|
+
UiSidebarGroup,
|
|
1018
|
+
UiSidebarGroupContent,
|
|
1019
|
+
UiSidebarGroupLabel,
|
|
1020
|
+
UiSidebarHeaderTrigger,
|
|
1021
|
+
UiSidebarInset,
|
|
1022
|
+
UiSidebarMenu,
|
|
1023
|
+
UiSidebarMenuButton,
|
|
1024
|
+
UiSidebarMenuItem,
|
|
1025
|
+
UiSidebarProvider,
|
|
1026
|
+
UiSidebarRail,
|
|
1027
|
+
useSidebar,
|
|
1028
|
+
} from '@aleph-alpha/ui-library'
|
|
1029
|
+
import { Bot, Database, BarChart3, MessageSquare, Command } from 'lucide-vue-next'
|
|
1030
|
+
|
|
1031
|
+
const items = [
|
|
1032
|
+
{ title: 'Playground', icon: Bot },
|
|
1033
|
+
{ title: 'Models', icon: Database },
|
|
1034
|
+
{ title: 'Evaluations', icon: BarChart3 },
|
|
1035
|
+
{ title: 'Conversations', icon: MessageSquare },
|
|
1036
|
+
]
|
|
1037
|
+
|
|
1038
|
+
// useSidebar() must be called inside <UiSidebarProvider>.
|
|
1039
|
+
// Use a child component or <script setup> in a component nested within the provider.
|
|
1040
|
+
</script>
|
|
1041
|
+
|
|
1042
|
+
<template>
|
|
1043
|
+
<UiSidebarProvider>
|
|
1044
|
+
<!-- Wrap content in a child component that calls useSidebar() -->
|
|
1045
|
+
<SidebarLayout :items="items" />
|
|
1046
|
+
</UiSidebarProvider>
|
|
1047
|
+
</template>
|
|
1048
|
+
|
|
1049
|
+
<!-- Child component (e.g. SidebarLayout.vue) -->
|
|
1050
|
+
<script setup lang="ts">
|
|
1051
|
+
import { useSidebar } from '@aleph-alpha/ui-library'
|
|
1052
|
+
|
|
1053
|
+
const { state, open, setOpen, toggleSidebar } = useSidebar()
|
|
1054
|
+
</script>
|
|
1055
|
+
|
|
1056
|
+
<template>
|
|
1057
|
+
<UiSidebar><!-- ... --></UiSidebar>
|
|
1058
|
+
<UiSidebarInset>
|
|
1059
|
+
<div class="p-6 space-y-4">
|
|
1060
|
+
<p>Sidebar is <strong>{{ state }}</strong></p>
|
|
1061
|
+
<button @click="toggleSidebar()">Toggle</button>
|
|
1062
|
+
<button @click="setOpen(true)">Open</button>
|
|
1063
|
+
<button @click="setOpen(false)">Close</button>
|
|
1064
|
+
</div>
|
|
1065
|
+
</UiSidebarInset>
|
|
1066
|
+
</template>`;
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* Programmatic sidebar control via the `useSidebar()` composable. The composable must be called
|
|
1070
|
+
* inside a component rendered within `<UiSidebarProvider>`. It returns reactive state (`state`, `open`)
|
|
1071
|
+
* and methods (`toggleSidebar`, `setOpen`) to control the sidebar from anywhere in the provider tree.
|
|
1072
|
+
*
|
|
1073
|
+
* This is the recommended pattern for controlling the sidebar from outside — e.g. opening it
|
|
1074
|
+
* from a toolbar button, closing it after navigation, or syncing state with a store.
|
|
1075
|
+
*/
|
|
1076
|
+
export const ProgrammaticControl: Story = {
|
|
1077
|
+
render: (args) => ({
|
|
1078
|
+
components: {
|
|
1079
|
+
UiSidebar,
|
|
1080
|
+
UiSidebarContent,
|
|
1081
|
+
UiSidebarGroup,
|
|
1082
|
+
UiSidebarGroupContent,
|
|
1083
|
+
UiSidebarGroupLabel,
|
|
1084
|
+
UiSidebarHeaderTrigger,
|
|
1085
|
+
UiSidebarInset,
|
|
1086
|
+
UiSidebarMenu,
|
|
1087
|
+
UiSidebarMenuButton,
|
|
1088
|
+
UiSidebarMenuItem,
|
|
1089
|
+
UiSidebarProvider,
|
|
1090
|
+
UiSidebarRail,
|
|
1091
|
+
Bot,
|
|
1092
|
+
Database,
|
|
1093
|
+
BarChart3,
|
|
1094
|
+
MessageSquare,
|
|
1095
|
+
Command,
|
|
1096
|
+
// Inline child component that uses useSidebar() — in real apps this would be a separate .vue file
|
|
1097
|
+
SidebarContent: defineComponent({
|
|
1098
|
+
setup() {
|
|
1099
|
+
const { state, toggleSidebar, setOpen } = useSidebar();
|
|
1100
|
+
return { state, toggleSidebar, setOpen };
|
|
1101
|
+
},
|
|
1102
|
+
template: `<slot :state="state" :toggleSidebar="toggleSidebar" :setOpen="setOpen" />`,
|
|
1103
|
+
}),
|
|
1104
|
+
},
|
|
1105
|
+
setup() {
|
|
1106
|
+
const items = [
|
|
1107
|
+
{ title: 'Playground', icon: Bot },
|
|
1108
|
+
{ title: 'Models', icon: Database },
|
|
1109
|
+
{ title: 'Evaluations', icon: BarChart3 },
|
|
1110
|
+
{ title: 'Conversations', icon: MessageSquare },
|
|
1111
|
+
];
|
|
1112
|
+
return { args, items };
|
|
1113
|
+
},
|
|
1114
|
+
template: `
|
|
1115
|
+
<UiSidebarProvider>
|
|
1116
|
+
<UiSidebar :side="args.side" :variant="args.variant" :collapsible="args.collapsible">
|
|
1117
|
+
<UiSidebarHeaderTrigger>
|
|
1118
|
+
<template #logo>
|
|
1119
|
+
<div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
|
|
1120
|
+
<Command class="size-4" />
|
|
1121
|
+
</div>
|
|
1122
|
+
</template>
|
|
1123
|
+
<span class="truncate font-semibold">Acme AI</span>
|
|
1124
|
+
<span class="truncate text-xs">Enterprise</span>
|
|
1125
|
+
</UiSidebarHeaderTrigger>
|
|
1126
|
+
<UiSidebarContent>
|
|
1127
|
+
<UiSidebarGroup>
|
|
1128
|
+
<UiSidebarGroupLabel>Platform</UiSidebarGroupLabel>
|
|
1129
|
+
<UiSidebarGroupContent>
|
|
1130
|
+
<UiSidebarMenu>
|
|
1131
|
+
<UiSidebarMenuItem v-for="item in items" :key="item.title">
|
|
1132
|
+
<UiSidebarMenuButton :tooltip="item.title">
|
|
1133
|
+
<component :is="item.icon" />
|
|
1134
|
+
<span>{{ item.title }}</span>
|
|
1135
|
+
</UiSidebarMenuButton>
|
|
1136
|
+
</UiSidebarMenuItem>
|
|
1137
|
+
</UiSidebarMenu>
|
|
1138
|
+
</UiSidebarGroupContent>
|
|
1139
|
+
</UiSidebarGroup>
|
|
1140
|
+
</UiSidebarContent>
|
|
1141
|
+
<UiSidebarRail />
|
|
1142
|
+
</UiSidebar>
|
|
1143
|
+
<UiSidebarInset>
|
|
1144
|
+
<SidebarContent v-slot="{ state, toggleSidebar, setOpen }">
|
|
1145
|
+
<div class="p-6">
|
|
1146
|
+
<div class="mb-6">
|
|
1147
|
+
<h2 class="text-lg font-semibold mb-1">Programmatic Control</h2>
|
|
1148
|
+
<p class="text-sm text-muted-foreground">
|
|
1149
|
+
Use <code class="rounded bg-muted px-1.5 py-0.5 text-xs">useSidebar()</code> inside the provider tree to control the sidebar from any component.
|
|
1150
|
+
</p>
|
|
1151
|
+
</div>
|
|
1152
|
+
<div class="flex items-center gap-3 mb-6">
|
|
1153
|
+
<span class="text-sm">State: <strong>{{ state }}</strong></span>
|
|
1154
|
+
</div>
|
|
1155
|
+
<div class="flex flex-wrap gap-2">
|
|
1156
|
+
<button
|
|
1157
|
+
class="inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-4 border border-input bg-background hover:bg-accent hover:text-accent-foreground"
|
|
1158
|
+
@click="toggleSidebar()"
|
|
1159
|
+
>
|
|
1160
|
+
Toggle sidebar
|
|
1161
|
+
</button>
|
|
1162
|
+
<button
|
|
1163
|
+
class="inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-4 border border-input bg-background hover:bg-accent hover:text-accent-foreground"
|
|
1164
|
+
@click="setOpen(true)"
|
|
1165
|
+
>
|
|
1166
|
+
Open
|
|
1167
|
+
</button>
|
|
1168
|
+
<button
|
|
1169
|
+
class="inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-4 border border-input bg-background hover:bg-accent hover:text-accent-foreground"
|
|
1170
|
+
@click="setOpen(false)"
|
|
1171
|
+
>
|
|
1172
|
+
Close
|
|
1173
|
+
</button>
|
|
1174
|
+
</div>
|
|
1175
|
+
</div>
|
|
1176
|
+
</SidebarContent>
|
|
1177
|
+
</UiSidebarInset>
|
|
1178
|
+
</UiSidebarProvider>
|
|
1179
|
+
`,
|
|
1180
|
+
}),
|
|
1181
|
+
parameters: {
|
|
1182
|
+
docs: {
|
|
1183
|
+
source: {
|
|
1184
|
+
code: programmaticControlTemplateSource,
|
|
1185
|
+
},
|
|
1186
|
+
},
|
|
1187
|
+
},
|
|
1188
|
+
};
|
|
@@ -7,12 +7,10 @@
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
const props = defineProps<UiSidebarProviderProps>();
|
|
10
|
-
|
|
11
|
-
const open = defineModel<boolean | undefined>('open');
|
|
12
10
|
</script>
|
|
13
11
|
|
|
14
12
|
<template>
|
|
15
|
-
<ShadcnSidebarProvider
|
|
13
|
+
<ShadcnSidebarProvider :default-open="props.defaultOpen">
|
|
16
14
|
<slot />
|
|
17
15
|
</ShadcnSidebarProvider>
|
|
18
16
|
</template>
|
|
@@ -12,20 +12,17 @@ export type UiSidebarMenuButtonSize = 'default' | 'sm' | 'lg';
|
|
|
12
12
|
|
|
13
13
|
export type UiSidebarMenuSubButtonSize = 'sm' | 'md';
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Wraps the sidebar and manages its open/closed state.
|
|
17
|
+
* Omit `default-open` to use cookie-based persistence (falls back to expanded).
|
|
18
|
+
*/
|
|
15
19
|
export interface UiSidebarProviderProps {
|
|
16
20
|
/**
|
|
17
|
-
* The
|
|
18
|
-
* If not provided, the
|
|
21
|
+
* The initial open state of the sidebar.
|
|
22
|
+
* If not provided, the inner provider uses cookie-based persistence
|
|
19
23
|
* (falls back to expanded if no cookie exists).
|
|
20
24
|
*/
|
|
21
25
|
defaultOpen?: boolean;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* The controlled open state of the sidebar.
|
|
25
|
-
* - Omit for uncontrolled mode (component manages state internally)
|
|
26
|
-
* - Use `v-model:open` for controlled mode
|
|
27
|
-
*/
|
|
28
|
-
open?: boolean;
|
|
29
26
|
}
|
|
30
27
|
|
|
31
28
|
/**
|