@rokkit/ui 1.0.0-next.125 → 1.0.0-next.127
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/README.md +198 -101
- package/package.json +52 -34
- package/src/components/BreadCrumbs.svelte +82 -0
- package/src/components/Button.svelte +87 -0
- package/src/components/ButtonGroup.svelte +18 -0
- package/src/components/Card.svelte +61 -0
- package/src/components/Carousel.svelte +169 -0
- package/src/components/Code.svelte +185 -0
- package/src/components/Connector.svelte +46 -0
- package/src/components/FloatingAction.svelte +331 -0
- package/src/components/FloatingNavigation.svelte +228 -0
- package/src/components/ItemContent.svelte +24 -0
- package/src/components/List.svelte +476 -0
- package/src/components/Menu.svelte +421 -0
- package/src/components/MultiSelect.svelte +521 -0
- package/src/components/PaletteManager.svelte +354 -0
- package/src/components/Pill.svelte +78 -0
- package/src/components/ProgressBar.svelte +31 -0
- package/src/components/Range.svelte +325 -0
- package/src/components/Rating.svelte +91 -0
- package/src/components/Reveal.svelte +58 -0
- package/src/components/SearchFilter.svelte +80 -0
- package/src/components/Select.svelte +585 -0
- package/src/{Shine.svelte → components/Shine.svelte} +29 -21
- package/src/components/Stepper.svelte +169 -0
- package/src/components/Switch.svelte +75 -0
- package/src/components/Table.svelte +243 -0
- package/src/components/Tabs.svelte +268 -0
- package/src/components/Tilt.svelte +68 -0
- package/src/components/Timeline.svelte +61 -0
- package/src/components/Toggle.svelte +157 -0
- package/src/components/Toolbar.svelte +307 -0
- package/src/components/ToolbarGroup.svelte +17 -0
- package/src/components/Tree.svelte +613 -0
- package/src/components/index.ts +33 -0
- package/src/index.ts +41 -0
- package/src/types/button.ts +83 -0
- package/src/types/code.ts +46 -0
- package/src/types/floating-action.ts +118 -0
- package/src/types/floating-navigation.ts +68 -0
- package/src/types/index.ts +53 -0
- package/src/types/item-proxy.ts +358 -0
- package/src/types/list.ts +196 -0
- package/src/types/menu.ts +195 -0
- package/src/types/palette.ts +143 -0
- package/src/types/range.ts +51 -0
- package/src/types/search-filter.ts +67 -0
- package/src/types/select.ts +206 -0
- package/src/types/switch.ts +64 -0
- package/src/types/table.ts +210 -0
- package/src/types/tabs.ts +124 -0
- package/src/types/timeline.ts +51 -0
- package/src/types/toggle.ts +109 -0
- package/src/types/toolbar.ts +164 -0
- package/src/types/tree.ts +259 -0
- package/src/utils/palette.ts +582 -0
- package/src/utils/shiki.ts +122 -0
- package/dist/constants.d.ts +0 -2
- package/dist/index.d.ts +0 -41
- package/dist/lib/fields.d.ts +0 -16
- package/dist/lib/form.d.ts +0 -95
- package/dist/lib/index.d.ts +0 -6
- package/dist/lib/layout.d.ts +0 -7
- package/dist/lib/nested.d.ts +0 -48
- package/dist/lib/schema.d.ts +0 -7
- package/dist/lib/select.d.ts +0 -8
- package/dist/lib/tree.d.ts +0 -9
- package/dist/tree/List.spec.svelte.d.ts +0 -1
- package/dist/tree/Node.spec.svelte.d.ts +0 -1
- package/dist/tree/Root.spec.svelte.d.ts +0 -1
- package/dist/types.d.ts +0 -5
- package/dist/wrappers/index.d.ts +0 -3
- package/src/Accordion.svelte +0 -118
- package/src/BreadCrumbs.svelte +0 -32
- package/src/Button.svelte +0 -57
- package/src/Calendar.svelte +0 -93
- package/src/Card.svelte +0 -45
- package/src/Carousel.svelte +0 -49
- package/src/CheckBox.svelte +0 -56
- package/src/Connector.svelte +0 -40
- package/src/DropDown.svelte +0 -68
- package/src/DropSearch.svelte +0 -37
- package/src/Fillable.svelte +0 -19
- package/src/GraphPaper.svelte +0 -43
- package/src/Icon.svelte +0 -81
- package/src/Item.svelte +0 -25
- package/src/Link.svelte +0 -21
- package/src/List.svelte +0 -89
- package/src/ListBody.svelte +0 -43
- package/src/Message.svelte +0 -11
- package/src/MultiSelect.svelte +0 -48
- package/src/NestedList.svelte +0 -78
- package/src/NestedPaginator.svelte +0 -63
- package/src/Node.svelte +0 -76
- package/src/Overlay.svelte +0 -21
- package/src/PageNavigator.svelte +0 -94
- package/src/PickOne.svelte +0 -60
- package/src/Pill.svelte +0 -41
- package/src/ProgressBar.svelte +0 -21
- package/src/ProgressDots.svelte +0 -53
- package/src/RadioGroup.svelte +0 -52
- package/src/Range.svelte +0 -45
- package/src/RangeMinMax.svelte +0 -124
- package/src/RangeSlider.svelte +0 -79
- package/src/RangeTick.svelte +0 -28
- package/src/Rating.svelte +0 -95
- package/src/ResponsiveGrid.svelte +0 -88
- package/src/Scrollable.svelte +0 -7
- package/src/Select.svelte +0 -114
- package/src/Separator.svelte +0 -1
- package/src/Slider.svelte +0 -14
- package/src/SlidingColumns.svelte +0 -50
- package/src/Stage.svelte +0 -41
- package/src/Stepper.svelte +0 -66
- package/src/Summary.svelte +0 -22
- package/src/Switch.svelte +0 -106
- package/src/TableCell.svelte +0 -51
- package/src/TableHeaderCell.svelte +0 -54
- package/src/Tabs.svelte +0 -176
- package/src/Tilt.svelte +0 -66
- package/src/Toggle.svelte +0 -58
- package/src/ToggleThemeMode.svelte +0 -23
- package/src/Tree.svelte +0 -80
- package/src/TreeTable.svelte +0 -171
- package/src/ValidationReport.svelte +0 -23
- package/src/constants.js +0 -4
- package/src/index.js +0 -48
- package/src/lib/fields.js +0 -118
- package/src/lib/form.js +0 -72
- package/src/lib/index.js +0 -13
- package/src/lib/layout.js +0 -63
- package/src/lib/nested.js +0 -192
- package/src/lib/schema.js +0 -32
- package/src/lib/select.js +0 -38
- package/src/lib/tree.js +0 -22
- package/src/tree/List.spec.svelte.js +0 -84
- package/src/tree/List.svelte +0 -78
- package/src/tree/Node.spec.svelte.js +0 -104
- package/src/tree/Node.svelte +0 -80
- package/src/tree/Root.spec.svelte.js +0 -63
- package/src/tree/Root.svelte +0 -81
- package/src/types.js +0 -9
- package/src/wrappers/Category.svelte +0 -27
- package/src/wrappers/Section.svelte +0 -16
- package/src/wrappers/Wrapper.svelte +0 -12
- package/src/wrappers/index.js +0 -3
package/README.md
CHANGED
|
@@ -1,123 +1,220 @@
|
|
|
1
1
|
# @rokkit/ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Data driven UI components for Rokkit applications.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
```
|
|
8
|
-
|
|
7
|
+
```bash
|
|
8
|
+
bun add @rokkit/ui
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## Components
|
|
12
|
+
|
|
13
|
+
### Menu
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
A flexible, data-driven dropdown menu component with support for:
|
|
16
|
+
|
|
17
|
+
- Flat or grouped menu items
|
|
18
|
+
- Custom field mapping for any data structure
|
|
19
|
+
- Icons, descriptions, and disabled states
|
|
20
|
+
- Size variants (sm, md, lg)
|
|
21
|
+
- Keyboard navigation
|
|
22
|
+
- Full accessibility (ARIA)
|
|
23
|
+
|
|
24
|
+
```svelte
|
|
25
|
+
<script>
|
|
26
|
+
import { Menu } from '@rokkit/ui'
|
|
27
|
+
|
|
28
|
+
const options = [
|
|
29
|
+
{ text: 'Copy', icon: 'i-solar:copy-bold', value: 'copy' },
|
|
30
|
+
{ text: 'Paste', icon: 'i-solar:clipboard-bold', value: 'paste' },
|
|
31
|
+
{ text: 'Delete', icon: 'i-solar:trash-bold', value: 'delete', disabled: true }
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
function handleSelect(value, item) {
|
|
35
|
+
console.log('Selected:', value, item)
|
|
36
|
+
}
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<Menu {options} label="Actions" icon="i-solar:menu-dots-bold" onselect={handleSelect} />
|
|
15
40
|
```
|
|
16
41
|
|
|
17
|
-
|
|
42
|
+
#### Grouped Options
|
|
18
43
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
- **PageNavigator** - Component for paginating through content
|
|
46
|
-
- **NestedPaginator** - Pagination for nested data structures
|
|
47
|
-
|
|
48
|
-
### Form Components
|
|
49
|
-
|
|
50
|
-
- **InputField** - Base component for form inputs
|
|
51
|
-
- **Form** - Container for form elements with built-in validation
|
|
52
|
-
- **FieldLayout** - Layout component for form fields
|
|
53
|
-
- **CheckBox** - Checkbox input component
|
|
54
|
-
- **RadioGroup** - Group of radio button options
|
|
55
|
-
- **Toggle** - Toggle switch component
|
|
56
|
-
- **Switch** - Switch control component
|
|
57
|
-
- **Select** - Dropdown select component
|
|
58
|
-
- **MultiSelect** - Multiple selection dropdown component
|
|
59
|
-
- **DropDown** - Dropdown menu component
|
|
60
|
-
- **DropSearch** - Searchable dropdown component
|
|
61
|
-
- **Range** - Range selection component
|
|
62
|
-
- **RangeMinMax** - Range with minimum and maximum values
|
|
63
|
-
- **RangeSlider** - Slider control for selecting from a range
|
|
64
|
-
- **RangeTick** - Range with tick marks
|
|
65
|
-
- **Calendar** - Date selection calendar
|
|
66
|
-
- **Rating** - Star rating component
|
|
67
|
-
|
|
68
|
-
### Data Components
|
|
69
|
-
|
|
70
|
-
- **DataEditor** - Component for editing structured data
|
|
71
|
-
- **ListEditor** - Component for editing lists
|
|
72
|
-
- **NestedEditor** - Component for editing nested data structures
|
|
73
|
-
- **List** - Display a list of items
|
|
74
|
-
- **ListBody** - Container for list items
|
|
75
|
-
- **NestedList** - Display nested/hierarchical lists
|
|
76
|
-
- **Table** - Table component for structured data (alias for TreeTable)
|
|
77
|
-
- **TreeTable** - Table component with support for hierarchical data
|
|
78
|
-
- **Tree** - Tree view for hierarchical data
|
|
79
|
-
- **Node** - Individual node within a tree
|
|
80
|
-
|
|
81
|
-
### Progress & Navigation Components
|
|
82
|
-
|
|
83
|
-
- **Stepper** - Step-by-step process indicator
|
|
84
|
-
- **ProgressDots** - Progress indicator using dots
|
|
85
|
-
- **Carousel** - Image or content carousel
|
|
86
|
-
|
|
87
|
-
### Visual Effect Components
|
|
88
|
-
|
|
89
|
-
- **Shine** - Add shine effect to elements
|
|
90
|
-
- **Tilt** - Add tilt effect to elements
|
|
91
|
-
- **Scrollable** - Scrollable container with custom scrollbars
|
|
92
|
-
|
|
93
|
-
### Theme Components
|
|
94
|
-
|
|
95
|
-
- **ToggleThemeMode** - Toggle between light and dark themes
|
|
96
|
-
|
|
97
|
-
## Usage Example
|
|
44
|
+
```svelte
|
|
45
|
+
<script>
|
|
46
|
+
const groupedOptions = [
|
|
47
|
+
{
|
|
48
|
+
text: 'Image',
|
|
49
|
+
children: [
|
|
50
|
+
{ text: 'Export as PNG', value: 'png' },
|
|
51
|
+
{ text: 'Export as SVG', value: 'svg' }
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
text: 'Data',
|
|
56
|
+
children: [
|
|
57
|
+
{ text: 'Export as CSV', value: 'csv' },
|
|
58
|
+
{ text: 'Export as JSON', value: 'json' }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<Menu options={groupedOptions} label="Export" />
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### Custom Field Mapping
|
|
68
|
+
|
|
69
|
+
Use the `fields` prop to map your data structure to Menu's expected fields:
|
|
98
70
|
|
|
99
71
|
```svelte
|
|
100
72
|
<script>
|
|
101
|
-
|
|
73
|
+
const items = [
|
|
74
|
+
{ name: 'Option A', id: 'a' },
|
|
75
|
+
{ name: 'Option B', id: 'b' }
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
const fields = {
|
|
79
|
+
text: 'name',
|
|
80
|
+
value: 'id'
|
|
81
|
+
}
|
|
102
82
|
</script>
|
|
103
83
|
|
|
104
|
-
<
|
|
105
|
-
<h2>Example Card</h2>
|
|
106
|
-
<p>This is an example of using the Card component</p>
|
|
107
|
-
<Button variant="primary" label="Click Me" leftIcon="check" />
|
|
108
|
-
</Card>
|
|
84
|
+
<Menu options={items} {fields} label="Select" />
|
|
109
85
|
```
|
|
110
86
|
|
|
111
|
-
|
|
87
|
+
### Custom Item Rendering
|
|
88
|
+
|
|
89
|
+
Use snippets to customize how menu items and group labels are rendered:
|
|
90
|
+
|
|
91
|
+
```svelte
|
|
92
|
+
<script>
|
|
93
|
+
import { Menu } from '@rokkit/ui'
|
|
112
94
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
95
|
+
const options = [
|
|
96
|
+
{ text: 'Normal Item', value: 'normal' },
|
|
97
|
+
{ text: 'Premium Feature', value: 'premium', snippet: 'premium' },
|
|
98
|
+
{ text: 'Special Offer', value: 'special', snippet: 'special' }
|
|
99
|
+
]
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<Menu {options}>
|
|
103
|
+
{#snippet item(menuItem, fields, handlers)}
|
|
104
|
+
<button onclick={handlers.onclick} onkeydown={handlers.onkeydown}>
|
|
105
|
+
🎯 {menuItem.text}
|
|
106
|
+
</button>
|
|
107
|
+
{/snippet}
|
|
108
|
+
|
|
109
|
+
{#snippet groupLabel(group, fields)}
|
|
110
|
+
<div class="custom-header">
|
|
111
|
+
📁 {group.text}
|
|
112
|
+
</div>
|
|
113
|
+
{/snippet}
|
|
114
|
+
|
|
115
|
+
{#snippet premium(menuItem, fields, handlers)}
|
|
116
|
+
<button onclick={handlers.onclick} onkeydown={handlers.onkeydown}>
|
|
117
|
+
🔒 Premium: {menuItem.text}
|
|
118
|
+
</button>
|
|
119
|
+
{/snippet}
|
|
120
|
+
|
|
121
|
+
{#snippet special(menuItem, fields, handlers)}
|
|
122
|
+
<button onclick={handlers.onclick} onkeydown={handlers.onkeydown}>
|
|
123
|
+
⭐ {menuItem.text}
|
|
124
|
+
</button>
|
|
125
|
+
{/snippet}
|
|
126
|
+
</Menu>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Snippet Resolution Order
|
|
130
|
+
|
|
131
|
+
1. **Per-item snippet**: If an item has a `snippet` field (e.g., `snippet: 'premium'`), the named snippet is used
|
|
132
|
+
2. **Generic `item` snippet**: Falls back to the `item` snippet if provided
|
|
133
|
+
3. **Default rendering**: Uses the built-in rendering if no custom snippet matches
|
|
134
|
+
|
|
135
|
+
#### Handlers Object
|
|
136
|
+
|
|
137
|
+
Custom snippets receive a `handlers` object with:
|
|
138
|
+
|
|
139
|
+
- `onclick: () => void` - Call to trigger item selection
|
|
140
|
+
- `onkeydown: (event) => void` - Forward keyboard events for accessibility
|
|
141
|
+
|
|
142
|
+
### Props
|
|
143
|
+
|
|
144
|
+
| Prop | Type | Default | Description |
|
|
145
|
+
| ------------ | ----------------------- | -------- | ---------------------------------- |
|
|
146
|
+
| `options` | `MenuItem[]` | `[]` | Array of menu items or groups |
|
|
147
|
+
| `fields` | `MenuFields` | `{}` | Field mapping configuration |
|
|
148
|
+
| `label` | `string` | `'Menu'` | Button label text |
|
|
149
|
+
| `icon` | `string` | - | Button icon class |
|
|
150
|
+
| `showArrow` | `boolean` | `true` | Show dropdown arrow indicator |
|
|
151
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size variant |
|
|
152
|
+
| `align` | `'left' \| 'right'` | `'left'` | Dropdown alignment |
|
|
153
|
+
| `disabled` | `boolean` | `false` | Disable the menu |
|
|
154
|
+
| `onselect` | `(value, item) => void` | - | Selection callback |
|
|
155
|
+
| `item` | `Snippet` | - | Custom snippet for rendering items |
|
|
156
|
+
| `groupLabel` | `Snippet` | - | Custom snippet for group headers |
|
|
157
|
+
| `class` | `string` | `''` | Additional CSS classes |
|
|
158
|
+
|
|
159
|
+
### CSS Custom Properties
|
|
160
|
+
|
|
161
|
+
```css
|
|
162
|
+
/* Trigger button */
|
|
163
|
+
--menu-trigger-bg
|
|
164
|
+
--menu-trigger-bg-hover
|
|
165
|
+
--menu-trigger-bg-active
|
|
166
|
+
--menu-trigger-border
|
|
167
|
+
--menu-trigger-border-hover
|
|
168
|
+
--menu-trigger-border-active
|
|
169
|
+
--menu-trigger-text
|
|
170
|
+
--menu-trigger-text-hover
|
|
171
|
+
--menu-focus-ring
|
|
172
|
+
|
|
173
|
+
/* Dropdown */
|
|
174
|
+
--menu-dropdown-bg
|
|
175
|
+
--menu-dropdown-border
|
|
176
|
+
--menu-dropdown-shadow
|
|
177
|
+
|
|
178
|
+
/* Items */
|
|
179
|
+
--menu-item-text
|
|
180
|
+
--menu-item-text-hover
|
|
181
|
+
--menu-item-bg-hover
|
|
182
|
+
--menu-item-bg-focus
|
|
183
|
+
--menu-item-icon
|
|
184
|
+
--menu-item-icon-hover
|
|
185
|
+
--menu-item-description
|
|
186
|
+
|
|
187
|
+
/* Groups */
|
|
188
|
+
--menu-group-label-color
|
|
189
|
+
--menu-divider-color
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Field Mapping
|
|
193
|
+
|
|
194
|
+
| Field | Default | Description |
|
|
195
|
+
| ------------- | --------------- | ------------------------- |
|
|
196
|
+
| `text` | `'text'` | Display text field |
|
|
197
|
+
| `value` | `'value'` | Value to emit on select |
|
|
198
|
+
| `icon` | `'icon'` | Icon class field |
|
|
199
|
+
| `description` | `'description'` | Secondary text field |
|
|
200
|
+
| `disabled` | `'disabled'` | Disabled state field |
|
|
201
|
+
| `children` | `'children'` | Children array for groups |
|
|
202
|
+
| `snippet` | `'snippet'` | Custom snippet name field |
|
|
203
|
+
|
|
204
|
+
## Types
|
|
205
|
+
|
|
206
|
+
All types are exported from the package:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import type {
|
|
210
|
+
MenuProps,
|
|
211
|
+
MenuFields,
|
|
212
|
+
MenuItem,
|
|
213
|
+
MenuItemSnippet,
|
|
214
|
+
MenuGroupLabelSnippet,
|
|
215
|
+
MenuItemHandlers
|
|
216
|
+
} from '@rokkit/ui'
|
|
217
|
+
```
|
|
121
218
|
|
|
122
219
|
## License
|
|
123
220
|
|
package/package.json
CHANGED
|
@@ -1,44 +1,62 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rokkit/ui",
|
|
3
|
-
"version": "1.0.0-next.
|
|
4
|
-
"description": "Data driven UI components
|
|
5
|
-
"author": "Jerry Thomas <me@jerrythomas.name>",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"module": "src/index.js",
|
|
3
|
+
"version": "1.0.0-next.127",
|
|
4
|
+
"description": "Data driven UI components for Rokkit applications",
|
|
8
5
|
"type": "module",
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
},
|
|
12
|
-
"scripts": {
|
|
13
|
-
"prepublishOnly": "bun clean && bun tsc --project tsconfig.build.json",
|
|
14
|
-
"clean": "rm -rf dist",
|
|
15
|
-
"build": "bun prepublishOnly"
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"src/**/*.js",
|
|
19
|
-
"src/**/*.svelte",
|
|
20
|
-
"dist/**/*.d.ts",
|
|
21
|
-
"README.md",
|
|
22
|
-
"package.json"
|
|
23
|
-
],
|
|
6
|
+
"svelte": "./src/index.ts",
|
|
7
|
+
"types": "./src/index.ts",
|
|
24
8
|
"exports": {
|
|
25
|
-
"./package.json": "./package.json",
|
|
26
|
-
"./utils": "./src/lib/index.js",
|
|
27
9
|
".": {
|
|
28
|
-
"types": "./
|
|
29
|
-
"
|
|
30
|
-
"
|
|
10
|
+
"types": "./src/index.ts",
|
|
11
|
+
"svelte": "./src/index.ts",
|
|
12
|
+
"default": "./src/index.ts"
|
|
13
|
+
},
|
|
14
|
+
"./types": {
|
|
15
|
+
"types": "./src/types/index.ts",
|
|
16
|
+
"default": "./src/types/index.ts"
|
|
17
|
+
},
|
|
18
|
+
"./utils/palette": {
|
|
19
|
+
"types": "./src/utils/palette.ts",
|
|
20
|
+
"default": "./src/utils/palette.ts"
|
|
31
21
|
}
|
|
32
22
|
},
|
|
23
|
+
"files": [
|
|
24
|
+
"src"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"check": "svelte-check --tsconfig ./tsconfig.json",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"test:watch": "vitest",
|
|
30
|
+
"build": "echo 'No build step needed for source-only package'"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"ui",
|
|
34
|
+
"components",
|
|
35
|
+
"svelte",
|
|
36
|
+
"menu",
|
|
37
|
+
"dropdown"
|
|
38
|
+
],
|
|
33
39
|
"dependencies": {
|
|
34
|
-
"@rokkit/
|
|
35
|
-
"@rokkit/
|
|
36
|
-
"@rokkit/
|
|
37
|
-
"@rokkit/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
40
|
+
"@rokkit/core": "1.0.0-next.127",
|
|
41
|
+
"@rokkit/data": "1.0.0-next.127",
|
|
42
|
+
"@rokkit/states": "1.0.0-next.127",
|
|
43
|
+
"@rokkit/actions": "1.0.0-next.127"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"shiki": "^3.23.0",
|
|
47
|
+
"svelte": "^5.0.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
|
51
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
52
|
+
"@testing-library/svelte": "^5.3.1",
|
|
53
|
+
"@testing-library/user-event": "^14.6.1",
|
|
54
|
+
"@vitest/browser": "^4.0.18",
|
|
55
|
+
"playwright": "^1.58.2",
|
|
56
|
+
"svelte": "^5.53.5",
|
|
57
|
+
"svelte-check": "^4.4.3",
|
|
58
|
+
"typescript": "^5.9.3",
|
|
59
|
+
"vite": "^7.3.1",
|
|
60
|
+
"vitest": "^4.0.18"
|
|
43
61
|
}
|
|
44
62
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte'
|
|
3
|
+
import { ItemProxy, type ItemFields } from '../types/item-proxy.js'
|
|
4
|
+
|
|
5
|
+
interface BreadCrumbsProps {
|
|
6
|
+
/** Array of breadcrumb items */
|
|
7
|
+
items?: unknown[]
|
|
8
|
+
/** Custom field mappings */
|
|
9
|
+
fields?: Partial<ItemFields>
|
|
10
|
+
/** Separator icon class (default: 'i-lucide:chevron-right') */
|
|
11
|
+
separator?: string
|
|
12
|
+
/** Callback when a breadcrumb is clicked */
|
|
13
|
+
onclick?: (value: unknown, item: unknown) => void
|
|
14
|
+
/** Custom snippet for rendering each crumb */
|
|
15
|
+
crumb?: Snippet<[ItemProxy, boolean]>
|
|
16
|
+
/** Additional CSS class */
|
|
17
|
+
class?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
items = [],
|
|
22
|
+
fields,
|
|
23
|
+
separator = 'i-lucide:chevron-right',
|
|
24
|
+
onclick,
|
|
25
|
+
crumb,
|
|
26
|
+
class: className = ''
|
|
27
|
+
}: BreadCrumbsProps = $props()
|
|
28
|
+
|
|
29
|
+
function createProxy(item: unknown): ItemProxy {
|
|
30
|
+
return new ItemProxy(item as Record<string, unknown>, fields)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function handleClick(proxy: ItemProxy) {
|
|
34
|
+
onclick?.(proxy.itemValue, proxy.original)
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
{#snippet defaultCrumb(proxy: ItemProxy, _isLast: boolean)}
|
|
39
|
+
{#if proxy.icon}
|
|
40
|
+
<span data-breadcrumb-icon class={proxy.icon} aria-hidden="true"></span>
|
|
41
|
+
{/if}
|
|
42
|
+
<span data-breadcrumb-label>{proxy.text}</span>
|
|
43
|
+
{/snippet}
|
|
44
|
+
|
|
45
|
+
<nav data-breadcrumbs class={className || undefined} aria-label="Breadcrumb">
|
|
46
|
+
<ol data-breadcrumb-list>
|
|
47
|
+
{#each items as item, index (index)}
|
|
48
|
+
{@const proxy = createProxy(item)}
|
|
49
|
+
{@const isLast = index === items.length - 1}
|
|
50
|
+
|
|
51
|
+
{#if index > 0}
|
|
52
|
+
<li data-breadcrumb-separator aria-hidden="true">
|
|
53
|
+
<span class={separator}></span>
|
|
54
|
+
</li>
|
|
55
|
+
{/if}
|
|
56
|
+
|
|
57
|
+
<li data-breadcrumb-item data-current={isLast || undefined}>
|
|
58
|
+
{#if isLast}
|
|
59
|
+
<span data-breadcrumb-current aria-current="page">
|
|
60
|
+
{#if crumb}
|
|
61
|
+
{@render crumb(proxy, isLast)}
|
|
62
|
+
{:else}
|
|
63
|
+
{@render defaultCrumb(proxy, isLast)}
|
|
64
|
+
{/if}
|
|
65
|
+
</span>
|
|
66
|
+
{:else}
|
|
67
|
+
<button
|
|
68
|
+
type="button"
|
|
69
|
+
data-breadcrumb-link
|
|
70
|
+
onclick={() => handleClick(proxy)}
|
|
71
|
+
>
|
|
72
|
+
{#if crumb}
|
|
73
|
+
{@render crumb(proxy, isLast)}
|
|
74
|
+
{:else}
|
|
75
|
+
{@render defaultCrumb(proxy, isLast)}
|
|
76
|
+
{/if}
|
|
77
|
+
</button>
|
|
78
|
+
{/if}
|
|
79
|
+
</li>
|
|
80
|
+
{/each}
|
|
81
|
+
</ol>
|
|
82
|
+
</nav>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ButtonProps } from '../types/button.js'
|
|
3
|
+
import { ItemProxy } from '../types/item-proxy.js'
|
|
4
|
+
import ItemContent from './ItemContent.svelte'
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
variant = 'default',
|
|
8
|
+
style = 'default',
|
|
9
|
+
size = 'md',
|
|
10
|
+
type = 'button',
|
|
11
|
+
label,
|
|
12
|
+
icon,
|
|
13
|
+
iconRight,
|
|
14
|
+
href,
|
|
15
|
+
target,
|
|
16
|
+
disabled = false,
|
|
17
|
+
loading = false,
|
|
18
|
+
onclick,
|
|
19
|
+
class: className = '',
|
|
20
|
+
children
|
|
21
|
+
}: ButtonProps = $props()
|
|
22
|
+
|
|
23
|
+
const isIconOnly = $derived(Boolean(icon) && !label && !children)
|
|
24
|
+
const isDisabled = $derived(disabled || loading)
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create an ItemProxy for default content rendering.
|
|
28
|
+
* Constructs a minimal item from button props.
|
|
29
|
+
*/
|
|
30
|
+
const proxy = $derived(
|
|
31
|
+
new ItemProxy({ text: label, icon, iconRight }, { text: 'text', icon: 'icon' })
|
|
32
|
+
)
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
{#snippet defaultContent()}
|
|
36
|
+
{#if loading}
|
|
37
|
+
<span data-button-spinner aria-hidden="true"></span>
|
|
38
|
+
{/if}
|
|
39
|
+
<ItemContent {proxy} />
|
|
40
|
+
{#if iconRight}
|
|
41
|
+
<span data-button-icon-right class={iconRight} aria-hidden="true"></span>
|
|
42
|
+
{/if}
|
|
43
|
+
{/snippet}
|
|
44
|
+
|
|
45
|
+
{#if href && !isDisabled}
|
|
46
|
+
<a
|
|
47
|
+
{href}
|
|
48
|
+
{target}
|
|
49
|
+
data-button
|
|
50
|
+
data-variant={variant}
|
|
51
|
+
data-style={style}
|
|
52
|
+
data-size={size}
|
|
53
|
+
data-icon-only={isIconOnly || undefined}
|
|
54
|
+
data-loading={loading || undefined}
|
|
55
|
+
class={className || undefined}
|
|
56
|
+
aria-label={label}
|
|
57
|
+
aria-busy={loading || undefined}
|
|
58
|
+
>
|
|
59
|
+
{#if children}
|
|
60
|
+
{@render children()}
|
|
61
|
+
{:else}
|
|
62
|
+
{@render defaultContent()}
|
|
63
|
+
{/if}
|
|
64
|
+
</a>
|
|
65
|
+
{:else}
|
|
66
|
+
<button
|
|
67
|
+
{type}
|
|
68
|
+
data-button
|
|
69
|
+
data-variant={variant}
|
|
70
|
+
data-style={style}
|
|
71
|
+
data-size={size}
|
|
72
|
+
data-disabled={isDisabled || undefined}
|
|
73
|
+
data-icon-only={isIconOnly || undefined}
|
|
74
|
+
data-loading={loading || undefined}
|
|
75
|
+
class={className || undefined}
|
|
76
|
+
disabled={isDisabled}
|
|
77
|
+
aria-label={label}
|
|
78
|
+
aria-busy={loading || undefined}
|
|
79
|
+
{onclick}
|
|
80
|
+
>
|
|
81
|
+
{#if children}
|
|
82
|
+
{@render children()}
|
|
83
|
+
{:else}
|
|
84
|
+
{@render defaultContent()}
|
|
85
|
+
{/if}
|
|
86
|
+
</button>
|
|
87
|
+
{/if}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ButtonGroupProps } from '../types/button.js'
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
size = 'md',
|
|
6
|
+
class: className = '',
|
|
7
|
+
children
|
|
8
|
+
}: ButtonGroupProps = $props()
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<div
|
|
12
|
+
data-button-group
|
|
13
|
+
data-size={size}
|
|
14
|
+
class={className || undefined}
|
|
15
|
+
role="group"
|
|
16
|
+
>
|
|
17
|
+
{@render children?.()}
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte'
|
|
3
|
+
|
|
4
|
+
interface CardProps {
|
|
5
|
+
/** Optional href to render as a link */
|
|
6
|
+
href?: string
|
|
7
|
+
/** Click handler (only applies when no href) */
|
|
8
|
+
onclick?: () => void
|
|
9
|
+
/** Additional CSS class */
|
|
10
|
+
class?: string
|
|
11
|
+
/** Card header snippet */
|
|
12
|
+
header?: Snippet
|
|
13
|
+
/** Card footer snippet */
|
|
14
|
+
footer?: Snippet
|
|
15
|
+
/** Card body content */
|
|
16
|
+
children?: Snippet
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
href,
|
|
21
|
+
onclick,
|
|
22
|
+
class: className = '',
|
|
23
|
+
header,
|
|
24
|
+
footer,
|
|
25
|
+
children
|
|
26
|
+
}: CardProps = $props()
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
{#snippet cardContent()}
|
|
30
|
+
{#if header}
|
|
31
|
+
<div data-card-header>
|
|
32
|
+
{@render header()}
|
|
33
|
+
</div>
|
|
34
|
+
{/if}
|
|
35
|
+
|
|
36
|
+
{#if children}
|
|
37
|
+
<div data-card-body>
|
|
38
|
+
{@render children()}
|
|
39
|
+
</div>
|
|
40
|
+
{/if}
|
|
41
|
+
|
|
42
|
+
{#if footer}
|
|
43
|
+
<div data-card-footer>
|
|
44
|
+
{@render footer()}
|
|
45
|
+
</div>
|
|
46
|
+
{/if}
|
|
47
|
+
{/snippet}
|
|
48
|
+
|
|
49
|
+
{#if href}
|
|
50
|
+
<a {href} data-card class={className || undefined}>
|
|
51
|
+
{@render cardContent()}
|
|
52
|
+
</a>
|
|
53
|
+
{:else if onclick}
|
|
54
|
+
<button type="button" data-card data-card-interactive class={className || undefined} {onclick}>
|
|
55
|
+
{@render cardContent()}
|
|
56
|
+
</button>
|
|
57
|
+
{:else}
|
|
58
|
+
<div data-card class={className || undefined}>
|
|
59
|
+
{@render cardContent()}
|
|
60
|
+
</div>
|
|
61
|
+
{/if}
|