alchemy-widget 0.3.0-alpha.1 → 0.3.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/CHANGELOG.md +16 -0
- package/CLAUDE.md +160 -0
- package/assets/stylesheets/alchemy_widgets.scss +0 -0
- package/assets/stylesheets/widget_picker.scss +283 -0
- package/element/20-add_area_element.js +19 -21
- package/element/30-base_toolbar_element.js +189 -2
- package/element/editor_toolbar_element.js +121 -1
- package/element/user_avatar_group_element.js +5 -0
- package/element/widget_picker_element.js +333 -0
- package/element/widget_toolbar_element.js +22 -137
- package/helper/document_watcher.js +41 -6
- package/helper/editor_toolbar_manager.js +112 -20
- package/helper/widgets/00-widget.js +256 -1
- package/helper/widgets/05-column.js +4 -0
- package/helper/widgets/05-list.js +55 -0
- package/helper/widgets/05-row.js +4 -0
- package/helper/widgets/alchemy_field_widget.js +5 -0
- package/helper/widgets/alchemy_form_widget.js +5 -0
- package/helper/widgets/alchemy_table_widget.js +4 -0
- package/helper/widgets/alchemy_tabs_widget.js +5 -0
- package/helper/widgets/hawkejs_template.js +4 -0
- package/helper/widgets/header.js +4 -0
- package/helper/widgets/html.js +4 -0
- package/helper/widgets/markdown.js +4 -0
- package/helper/widgets/sourcecode.js +4 -0
- package/helper/widgets/table_of_contents.js +4 -0
- package/helper/widgets/text.js +4 -0
- package/lib/conduit_extras.js +15 -4
- package/package.json +2 -2
- package/view/widget/elements/al_editor_toolbar.hwk +49 -1
- package/view/widget/elements/al_widget_toolbar.hwk +1 -1
- package/view/widget/elements/widget_picker.hwk +55 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 0.3.0 (2026-01-21)
|
|
2
|
+
|
|
3
|
+
* Add widget picker
|
|
4
|
+
* Add `recreate()` method to `EditorToolbarManager` and `DocumentWatcher` for automatic recovery after server restart
|
|
5
|
+
* Update `EditorToolbarManager` and `DocumentWatcher` to inherit from `Alchemy.Syncable.Specialized` for automatic type derivation and recreation support
|
|
6
|
+
* Add `replaced` event handler to `BaseToolbarElement` to automatically switch to new manager instance after server restart
|
|
7
|
+
* Add error handling in `attachDocumentWatcher()` for broken WebSocket connections
|
|
8
|
+
* Add null check in `UserAvatarGroup.setUsers()` to handle missing user info gracefully
|
|
9
|
+
* Fix `DocumentWatcher.addWatcher(conduit)` not awaiting the async `addWatcher(user_id, scene_id)` call, which caused viewer avatars to not appear on first edit after server restart
|
|
10
|
+
|
|
11
|
+
## 0.3.0-alpha.2 (2025-07-10)
|
|
12
|
+
|
|
13
|
+
* Make `main_class_names` widget config add classes to the first child of the wrapper
|
|
14
|
+
* Add `li_class_names` config to List widgets
|
|
15
|
+
* Don't return client-version of ToolbarManager on the server
|
|
16
|
+
|
|
1
17
|
## 0.3.0-alpha.1 (2024-02-15)
|
|
2
18
|
|
|
3
19
|
* Upgrade to Alchemy v1.4.0
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Alchemy Widget Development Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Widget system for AlchemyMVC. Widgets are configurable content blocks with drag-and-drop editing.
|
|
6
|
+
|
|
7
|
+
## Creating Custom Widgets
|
|
8
|
+
|
|
9
|
+
Widgets need two files:
|
|
10
|
+
- **Widget class** (`app/helper/widgets/`) - Logic and schema
|
|
11
|
+
- **Element class** (`app/element/`) - HTML rendering
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
// app/helper/widgets/my_widget.js
|
|
15
|
+
const MyWidget = Function.inherits('Alchemy.Widget', function MyWidget(config) {
|
|
16
|
+
MyWidget.super.call(this, config);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Metadata (optional) - category, description, icon, title
|
|
20
|
+
MyWidget.setCategory('data');
|
|
21
|
+
MyWidget.setDescription('Display custom data');
|
|
22
|
+
MyWidget.setIcon('cube');
|
|
23
|
+
MyWidget.setTitle('Data Table'); // Override auto-generated title
|
|
24
|
+
|
|
25
|
+
MyWidget.constitute(function prepareSchema() {
|
|
26
|
+
this.schema.addField('title', 'String');
|
|
27
|
+
this.schema.addField('style', 'Enum', {values: {default: 'Default', compact: 'Compact'}});
|
|
28
|
+
this.schema.addField('css_class', 'String', {widget_config_editable: true});
|
|
29
|
+
|
|
30
|
+
// Actions appear in widget toolbar
|
|
31
|
+
let refresh = this.createAction('refresh', 'Refresh');
|
|
32
|
+
refresh.setHandler((widget_el, handle) => widget_el.instance.rerender());
|
|
33
|
+
refresh.setTester(() => true);
|
|
34
|
+
refresh.setIcon('sync');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
MyWidget.setMethod(function populateWidget() {
|
|
38
|
+
let element = this.createElement('my-widget-element');
|
|
39
|
+
element.title = this.config.title;
|
|
40
|
+
this.widget.append(element);
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
// app/element/my_widget_element.js
|
|
46
|
+
const MyWidgetElement = Function.inherits('Alchemy.Element.App', 'MyWidgetElement');
|
|
47
|
+
MyWidgetElement.setTemplateFile('elements/my_widget_element');
|
|
48
|
+
MyWidgetElement.setAssignedProperty('title');
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Built-in Categories
|
|
52
|
+
|
|
53
|
+
| Category | Name | Icon | Description |
|
|
54
|
+
|----------|------|------|-------------|
|
|
55
|
+
| Layout | `layout` | table-columns | Structure and organize content |
|
|
56
|
+
| Text & Content | `text` | font | Text, headings, and rich content |
|
|
57
|
+
| Media | `media` | image | Images, videos, and embeds |
|
|
58
|
+
| Data & Forms | `data` | database | Tables, forms, and dynamic data |
|
|
59
|
+
| Navigation | `navigation` | compass | Menus, links, and navigation |
|
|
60
|
+
| Interactive | `interactive` | hand-pointer | Buttons, accordions, interactive elements |
|
|
61
|
+
| Advanced | `advanced` | code | Custom HTML, embeds, advanced widgets |
|
|
62
|
+
|
|
63
|
+
Custom categories: `MyWidget.setCategory('my-custom-category')` auto-generates title and uses puzzle-piece icon.
|
|
64
|
+
|
|
65
|
+
## Registering Custom Categories
|
|
66
|
+
|
|
67
|
+
Projects can register their own categories using `Widget.registerCategory()`:
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
// In app/config/bootstrap.js or similar
|
|
71
|
+
STAGES.getStage('load_app').addPostTask(function registerMyCategories() {
|
|
72
|
+
const Widget = Classes.Alchemy.Widget.Widget;
|
|
73
|
+
|
|
74
|
+
Widget.registerCategory('MONITORING', {
|
|
75
|
+
name : 'monitoring',
|
|
76
|
+
icon : 'chart-line',
|
|
77
|
+
order : 70, // Lower = earlier in list
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Required fields: `name`, `icon`. Optional: `order` (default: 90).
|
|
83
|
+
|
|
84
|
+
Category titles are automatically translated using the category name as the microcopy key with `widget=true category=true` filters.
|
|
85
|
+
|
|
86
|
+
## Toolbar Button Hooks
|
|
87
|
+
|
|
88
|
+
Plugins can register toolbar buttons without modifying shared code:
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
const EditorToolbarManager = Classes.Alchemy.Widget.EditorToolbarManager;
|
|
92
|
+
|
|
93
|
+
// Add buttons when a model is set (e.g., "Create" button)
|
|
94
|
+
EditorToolbarManager.registerModelButtonProvider((manager, model_name) => {
|
|
95
|
+
if (manager.scenario == 'my-scenario') {
|
|
96
|
+
manager.addTemplateToRender('buttons', 'my/toolbar/button', {model_name});
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Add buttons when a document is set (e.g., "Edit", "Preview" buttons)
|
|
101
|
+
EditorToolbarManager.registerDocumentButtonProvider((manager, doc, model, model_name, pk_val) => {
|
|
102
|
+
manager.addTemplateToRender('buttons', 'my/toolbar/edit_button', {
|
|
103
|
+
record_pk: pk_val,
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Widget Groups
|
|
109
|
+
|
|
110
|
+
The widget add-menu uses `alchemy.getClassGroup('widgets')`. Only widgets in this group appear.
|
|
111
|
+
|
|
112
|
+
**Direct inheritance (recommended):**
|
|
113
|
+
```javascript
|
|
114
|
+
const MyWidget = Function.inherits('Alchemy.Widget', function MyWidget(config) {
|
|
115
|
+
MyWidget.super.call(this, config);
|
|
116
|
+
});
|
|
117
|
+
// → Classes.Alchemy.Widget.MyWidget
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Abstract base class:**
|
|
121
|
+
```javascript
|
|
122
|
+
// 00_myapp_widget.js - DO NOT call startNewGroup()
|
|
123
|
+
const MyAppWidget = Function.inherits('Alchemy.Widget', 'MyApp.Widget');
|
|
124
|
+
MyAppWidget.makeAbstractClass();
|
|
125
|
+
// → Classes.MyApp.Widget.Widget (a new namespace)
|
|
126
|
+
|
|
127
|
+
// stats_widget.js
|
|
128
|
+
const StatsWidget = Function.inherits('MyApp.Widget', function StatsWidget(config) {
|
|
129
|
+
StatsWidget.super.call(this, config);
|
|
130
|
+
});
|
|
131
|
+
// → Classes.MyApp.Widget.StatsWidget
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Common mistake:**
|
|
135
|
+
```javascript
|
|
136
|
+
// WRONG - widgets won't appear in add menu
|
|
137
|
+
MyAppWidget.startNewGroup('myapp_widgets');
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Key Methods
|
|
141
|
+
|
|
142
|
+
- `populateWidget()` - Render content, append to `this.widget`
|
|
143
|
+
- `syncConfig()` - Called when editor stops, return updated config
|
|
144
|
+
- `_startEditor()` / `_stopEditor()` - Editing mode hooks
|
|
145
|
+
- `rerender()` - Re-render widget after config changes
|
|
146
|
+
|
|
147
|
+
## Built-in Widgets
|
|
148
|
+
|
|
149
|
+
`container`, `row`, `column`, `text`, `header`, `html`, `markdown`, `partial`, `alchemy_table`, `alchemy_form`, `alchemy_tabs`
|
|
150
|
+
|
|
151
|
+
## Gotchas
|
|
152
|
+
|
|
153
|
+
1. **`startNewGroup()` creates separate group** - Widgets won't appear in selector
|
|
154
|
+
2. **Widget files in `app/helper/widgets/`** - Not `app/lib/`
|
|
155
|
+
3. **`constitute()` doesn't need super** - All constitutes are queued and run in order automatically
|
|
156
|
+
4. **Abstract classes need `makeAbstractClass()`** - Otherwise appear in selector
|
|
157
|
+
5. **File numbering matters** - `00_base.js` loads before `10_child.js`
|
|
158
|
+
6. **Toolbar requires permission** - `'alchemy.widgets.toolbar'`
|
|
159
|
+
7. **Metadata before constitute()** - Call `setCategory()`, `setIcon()`, etc. after class definition but they can be anywhere (static methods set class properties)
|
|
160
|
+
8. **Default category is 'advanced'** - Widgets without explicit category appear in Advanced section
|
|
File without changes
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
al-widget-picker {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
min-width: 500px;
|
|
5
|
+
max-width: 700px;
|
|
6
|
+
max-height: 70vh;
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, sans-serif;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.widget-picker-loading {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
padding: 60px 20px;
|
|
17
|
+
color: rgba(0, 0, 0, 0.5);
|
|
18
|
+
|
|
19
|
+
.spinner {
|
|
20
|
+
width: 32px;
|
|
21
|
+
height: 32px;
|
|
22
|
+
border: 3px solid rgba(0, 0, 0, 0.1);
|
|
23
|
+
border-top-color: #2563eb;
|
|
24
|
+
border-radius: 50%;
|
|
25
|
+
animation: widget-picker-spin 0.8s linear infinite;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
p {
|
|
29
|
+
margin: 16px 0 0;
|
|
30
|
+
font-size: 14px;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@keyframes widget-picker-spin {
|
|
35
|
+
to {
|
|
36
|
+
transform: rotate(360deg);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.widget-picker {
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
flex: 1;
|
|
44
|
+
min-height: 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.widget-picker-header {
|
|
48
|
+
padding: 16px;
|
|
49
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
|
50
|
+
flex-shrink: 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.widget-picker-search {
|
|
54
|
+
width: 100%;
|
|
55
|
+
padding: 10px 14px;
|
|
56
|
+
font-size: 14px;
|
|
57
|
+
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
58
|
+
border-radius: 6px;
|
|
59
|
+
outline: none;
|
|
60
|
+
transition: border-color 0.15s, box-shadow 0.15s;
|
|
61
|
+
|
|
62
|
+
&:focus {
|
|
63
|
+
border-color: #2563eb;
|
|
64
|
+
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&::placeholder {
|
|
68
|
+
color: rgba(0, 0, 0, 0.4);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.widget-picker-body {
|
|
73
|
+
display: flex;
|
|
74
|
+
flex: 1;
|
|
75
|
+
min-height: 0;
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.widget-picker-categories {
|
|
80
|
+
width: 180px;
|
|
81
|
+
flex-shrink: 0;
|
|
82
|
+
padding: 12px;
|
|
83
|
+
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
|
84
|
+
overflow-y: auto;
|
|
85
|
+
background: rgba(0, 0, 0, 0.02);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.category-btn {
|
|
89
|
+
display: flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
gap: 10px;
|
|
92
|
+
width: 100%;
|
|
93
|
+
padding: 8px 12px;
|
|
94
|
+
margin-bottom: 4px;
|
|
95
|
+
font-size: 13px;
|
|
96
|
+
font-weight: 500;
|
|
97
|
+
color: rgba(0, 0, 0, 0.7);
|
|
98
|
+
background: transparent;
|
|
99
|
+
border: none;
|
|
100
|
+
border-radius: 6px;
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
transition: background-color 0.15s, color 0.15s;
|
|
103
|
+
text-align: left;
|
|
104
|
+
|
|
105
|
+
al-icon {
|
|
106
|
+
font-size: 16px;
|
|
107
|
+
opacity: 0.7;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
&:hover {
|
|
111
|
+
background: rgba(0, 0, 0, 0.05);
|
|
112
|
+
color: rgba(0, 0, 0, 0.9);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
&.active {
|
|
116
|
+
background: #2563eb;
|
|
117
|
+
color: white;
|
|
118
|
+
|
|
119
|
+
al-icon {
|
|
120
|
+
opacity: 1;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.widget-picker-list {
|
|
126
|
+
flex: 1;
|
|
127
|
+
min-height: 0;
|
|
128
|
+
padding: 12px 16px;
|
|
129
|
+
overflow-y: auto;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.widget-category-group {
|
|
133
|
+
margin-bottom: 20px;
|
|
134
|
+
|
|
135
|
+
&:last-child {
|
|
136
|
+
margin-bottom: 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
&[hidden] {
|
|
140
|
+
display: none;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.widget-category-title {
|
|
145
|
+
font-size: 11px;
|
|
146
|
+
font-weight: 600;
|
|
147
|
+
text-transform: uppercase;
|
|
148
|
+
letter-spacing: 0.5px;
|
|
149
|
+
color: rgba(0, 0, 0, 0.5);
|
|
150
|
+
margin: 0 0 8px 4px;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.widget-category-items {
|
|
154
|
+
display: flex;
|
|
155
|
+
flex-direction: column;
|
|
156
|
+
gap: 4px;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.widget-item {
|
|
160
|
+
display: flex;
|
|
161
|
+
align-items: flex-start;
|
|
162
|
+
gap: 12px;
|
|
163
|
+
width: 100%;
|
|
164
|
+
padding: 10px 12px;
|
|
165
|
+
background: transparent;
|
|
166
|
+
border: 1px solid transparent;
|
|
167
|
+
border-radius: 8px;
|
|
168
|
+
cursor: pointer;
|
|
169
|
+
transition: background-color 0.15s, border-color 0.15s;
|
|
170
|
+
text-align: left;
|
|
171
|
+
|
|
172
|
+
&:hover {
|
|
173
|
+
background: rgba(0, 0, 0, 0.04);
|
|
174
|
+
border-color: rgba(0, 0, 0, 0.08);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
&:focus {
|
|
178
|
+
outline: none;
|
|
179
|
+
background: rgba(37, 99, 235, 0.08);
|
|
180
|
+
border-color: rgba(37, 99, 235, 0.3);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
&[hidden] {
|
|
184
|
+
display: none;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.widget-item-icon {
|
|
189
|
+
display: flex;
|
|
190
|
+
align-items: center;
|
|
191
|
+
justify-content: center;
|
|
192
|
+
width: 36px;
|
|
193
|
+
height: 36px;
|
|
194
|
+
background: rgba(0, 0, 0, 0.06);
|
|
195
|
+
border-radius: 8px;
|
|
196
|
+
flex-shrink: 0;
|
|
197
|
+
|
|
198
|
+
al-icon {
|
|
199
|
+
font-size: 18px;
|
|
200
|
+
color: rgba(0, 0, 0, 0.6);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.widget-item-content {
|
|
205
|
+
display: flex;
|
|
206
|
+
flex-direction: column;
|
|
207
|
+
gap: 2px;
|
|
208
|
+
min-width: 0;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.widget-item-title {
|
|
212
|
+
font-size: 14px;
|
|
213
|
+
font-weight: 500;
|
|
214
|
+
color: rgba(0, 0, 0, 0.85);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.widget-item-description {
|
|
218
|
+
font-size: 12px;
|
|
219
|
+
color: rgba(0, 0, 0, 0.5);
|
|
220
|
+
line-height: 1.4;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.widget-picker-empty {
|
|
224
|
+
display: flex;
|
|
225
|
+
flex-direction: column;
|
|
226
|
+
align-items: center;
|
|
227
|
+
justify-content: center;
|
|
228
|
+
padding: 40px 20px;
|
|
229
|
+
text-align: center;
|
|
230
|
+
color: rgba(0, 0, 0, 0.4);
|
|
231
|
+
|
|
232
|
+
al-icon {
|
|
233
|
+
font-size: 32px;
|
|
234
|
+
margin-bottom: 12px;
|
|
235
|
+
opacity: 0.5;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
p {
|
|
239
|
+
margin: 0;
|
|
240
|
+
font-size: 14px;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
&[hidden] {
|
|
244
|
+
display: none;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Responsive: collapse categories on small screens
|
|
249
|
+
@media (max-width: 600px) {
|
|
250
|
+
al-widget-picker {
|
|
251
|
+
min-width: auto;
|
|
252
|
+
width: 100%;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.widget-picker-body {
|
|
256
|
+
flex-direction: column;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.widget-picker-categories {
|
|
260
|
+
width: 100%;
|
|
261
|
+
flex-direction: row;
|
|
262
|
+
flex-wrap: wrap;
|
|
263
|
+
gap: 4px;
|
|
264
|
+
padding: 8px 12px;
|
|
265
|
+
border-right: none;
|
|
266
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.category-btn {
|
|
270
|
+
width: auto;
|
|
271
|
+
margin-bottom: 0;
|
|
272
|
+
padding: 6px 10px;
|
|
273
|
+
font-size: 12px;
|
|
274
|
+
|
|
275
|
+
span {
|
|
276
|
+
display: none;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
al-icon {
|
|
280
|
+
margin: 0;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
@@ -20,15 +20,13 @@ let AddArea = Function.inherits('Alchemy.Element.Widget.Base', function WidgetAd
|
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* Show the
|
|
23
|
+
* Show the widget picker dialog
|
|
24
24
|
*
|
|
25
25
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
26
26
|
* @since 0.1.0
|
|
27
|
-
* @version 0.
|
|
27
|
+
* @version 0.3.0
|
|
28
28
|
*/
|
|
29
|
-
AddArea.setMethod(function showTypes(event) {
|
|
30
|
-
|
|
31
|
-
let that = this;
|
|
29
|
+
AddArea.setMethod(async function showTypes(event) {
|
|
32
30
|
|
|
33
31
|
let context_button = document.querySelector('al-widget-context');
|
|
34
32
|
|
|
@@ -36,25 +34,25 @@ AddArea.setMethod(function showTypes(event) {
|
|
|
36
34
|
context_button.forceUnselection();
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
// Create the widget picker element
|
|
38
|
+
let picker = this.createElement('al-widget-picker');
|
|
39
|
+
picker.target_container = this.parentElement;
|
|
40
|
+
picker.addEventListener('select', (e) => {
|
|
41
|
+
this.parentElement.addWidget(e.detail.type_name);
|
|
42
|
+
});
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
// Create the dialog
|
|
45
|
+
let dialog = this.createElement('he-dialog');
|
|
46
|
+
dialog.setAttribute('dialog-title', 'Add Widget');
|
|
47
|
+
dialog.classList.add('widget-picker-dialog');
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
});
|
|
55
|
-
}
|
|
49
|
+
// Wrap picker in a slot container
|
|
50
|
+
let slot = document.createElement('div');
|
|
51
|
+
slot.setAttribute('slot', 'main');
|
|
52
|
+
slot.append(picker);
|
|
53
|
+
dialog.append(slot);
|
|
56
54
|
|
|
57
|
-
|
|
55
|
+
document.body.append(dialog);
|
|
58
56
|
});
|
|
59
57
|
|
|
60
58
|
/**
|