ember-tribe 2.6.7 → 2.6.8

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.
Files changed (2) hide show
  1. package/README.md +416 -236
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -26,7 +26,18 @@ The addon automatically configures following essential packages:
26
26
 
27
27
  **Ember Addons:** `ember-cli-dotenv`, `ember-cli-sass`, `ember-modifier`, `ember-composable-helpers`, `ember-truth-helpers`, `ember-file-upload` , `ember-power-select`
28
28
 
29
- **NPM Packages:** `bootstrap`, `@popperjs/core`, `animate.css`, `video.js`, `swiper`, `howler`
29
+ **NPM Packages:** `bootstrap`, `@popperjs/core`, `animate.css`, `video.js`, `swiper`, `howler`, `sortablejs`, `papaparse`
30
+
31
+ **Built-in features that can be used in routes and components**:
32
+
33
+ - **Layout**: `table`, `figure`, `accordion`, `card`, `list-group`, `navbar`, `nav`, `tab`, `breadcrumb`
34
+ - **Interactive**: `button`, `button-group`, `dropdown`, `modal`, `collapse`, `offcanvas`, `pagination`, `popover`, `tooltip`, `swiper-carousel`, `videojs-player`, `howlerjs-player`, `input-field`, `input-group`, `textarea`, `checkbox`, `radio`, `range`, `select`, `multi-select`, `date`, `file-uploader`, `alert`, `badge`, `toast`, `placeholder`, `progress`, `spinner`, `scrollspy`
35
+
36
+ **Preinstalled services in ember-tribe**:
37
+
38
+ - `store`: Ember Data store for CRUD operations
39
+ - `router`: Ember router service for navigation
40
+ - `types`: Automatic model generation from backend tracks
30
41
 
31
42
  ---
32
43
 
@@ -50,6 +61,106 @@ installer.sh
50
61
 
51
62
  ---
52
63
 
64
+ ## Best Practices for AI generated code
65
+
66
+ These rules are **mandatory** for all Tribe-compatible code. Follow them strictly and do not deviate unless explicitly instructed.
67
+
68
+ ### General Rules
69
+
70
+ 1. **Bootstrap 5.x — Required Foundation**
71
+ Use Bootstrap 5.x as the sole design system for all layout, spacing, and responsive behaviour. Do not introduce custom CSS frameworks or utility libraries that conflict with Bootstrap. Follow Bootstrap conventions strictly.
72
+
73
+ 2. **Backend Field Access**
74
+ Always access backend fields through the `modules` object — e.g. `object.modules.field_name`. Never access backend fields directly.
75
+
76
+ 3. **npm Packages over Ember Addons**
77
+ When an npm package and an Ember addon offer equivalent functionality, always prefer the npm package for better long-term compatibility.
78
+
79
+ 4. **Icons — FontAwesome 6.x Only**
80
+ Use FontAwesome 6.x for all icons. Do not use any other icon library unless the project description explicitly specifies one.
81
+
82
+ 5. **Animations — Subtle and Purposeful**
83
+ If animations are needed, use `animate.css`. Keep animations subtle — prefer fades and minimal slides. Avoid anything that feels flashy or distracting.
84
+
85
+ 6. **EmberData Caching**
86
+ When data has already been loaded into the store, retrieve it with `peekRecord` instead of making a new network request.
87
+
88
+ 7. **Backend Filtering over Frontend Filtering**
89
+ For sorting and filtering data, always use `this.store.query` with backend query parameters. Do not filter or sort arrays on the frontend when the backend can do it.
90
+
91
+ ---
92
+
93
+ ### Storylang Architecture Rules
94
+
95
+ Follow this strict order of thinking when designing any feature:
96
+
97
+ > **Understand Types → Routes → Controllers → Helpers → Modifiers → Services → Components**
98
+
99
+ Always begin by understanding your data types, then define the routes that load that data, then wire up controllers to handle user actions, then extract reusable template logic into helpers, then isolate DOM behaviour into modifiers, then move app-wide logic into services, and finally — only when the project's scale warrants it — extract repeatable UI into components.
100
+
101
+ ---
102
+
103
+ **Types**
104
+
105
+ 11. **Start by Understanding Your Data**
106
+ Before writing any code, read the project description and `types.json` to understand the data model. Every architectural decision that follows — which routes to create, which services to build, whether components are even needed — depends on a clear understanding of the underlying types.
107
+
108
+ ---
109
+
110
+ **Routes**
111
+
112
+ 8. **Route Naming**
113
+ Match route names to user mental models. Use consistent, predictable naming conventions so that routes are self-documenting.
114
+
115
+ 9. **Routes Are for Fetching, Not Logic**
116
+ Routes should primarily perform read/fetch operations and pass data down to components or services. Keep JavaScript in routes to a minimum — business logic belongs in components and services, not routes.
117
+
118
+ 10. **Route Parameters**
119
+ Keep `get_vars` minimal and meaningful. Load only the data types that each specific route actually needs — avoid over-fetching.
120
+
121
+ ---
122
+
123
+ **Controllers**
124
+
125
+ 12. **Controllers Bridge Routes and Templates**
126
+ Controllers sit between routes and templates, handling query parameters, user actions, and transient UI state that belongs to a specific route. Keep controllers focused — they are not a place for business logic or data fetching.
127
+
128
+ 13. **Keep Controllers Thin**
129
+ Delegate complex logic to services. A controller should primarily expose tracked properties and actions that the corresponding template needs directly.
130
+
131
+ ---
132
+
133
+ **Helpers**
134
+
135
+ 17. **Helpers Must Be Pure and Stateless**
136
+ A helper receives input and returns output — nothing else. Helpers must have no side effects and must not interact with the store, services, or DOM.
137
+
138
+ ---
139
+
140
+ **Modifiers**
141
+
142
+ 18. **Modifiers Own All DOM Interaction**
143
+ Any direct DOM manipulation or third-party library initialisation must live in a modifier.
144
+
145
+ ---
146
+
147
+ **Services**
148
+
149
+ 15. **Services Are the Core Logic Layer**
150
+ Services hold the primary business logic of the application. They interact with both routes and components and are the single source of truth for app-wide behaviour.
151
+
152
+ 16. **Keep Services Stateless When Possible**
153
+ Avoid storing transient state in services. Where services must depend on one another, use dependency injection.
154
+
155
+ ---
156
+
157
+ **Components**
158
+
159
+ 14. **Components are not always required**
160
+ Before creating components, assess the scale of the project from its description. On small projects, fewer files means higher code readability — collapsing template logic directly into route templates is often the right call. On larger projects, the opposite is true: extracting repeatable UI into named components improves clarity, maintainability, and testability. Make this decision deliberately at the start, not as an afterthought.
161
+
162
+ ---
163
+
53
164
  ## Storylang CLI
54
165
 
55
166
  ember-tribe ships with a command-line tool called `storylang` that synchronises the `config/storylang.json` specification with the actual Ember project files.
@@ -96,33 +207,18 @@ The storylang.json file contains seven main sections:
96
207
 
97
208
  ```json
98
209
  {
99
- "implementation_approach": "...",
100
210
  "types": [...],
101
- "components": [...],
102
211
  "routes": [...],
103
- "services": [...],
104
212
  "helpers": [...],
105
- "modifiers": [...]
213
+ "modifiers": [...],
214
+ "services": [...],
215
+ "components": [...]
106
216
  }
107
217
  ```
108
218
 
109
219
  ### Section Definitions
110
220
 
111
- ### 1. Implementation Approach
112
-
113
- **Purpose**: Provides a high-level technical overview of how the frontend interface would work.
114
-
115
- **Format**:
116
-
117
- ```json
118
- {
119
- "implementation_approach": "Two-paragraph description explaining technical approach and key functionality."
120
- }
121
- ```
122
-
123
- ---
124
-
125
- ### 2. Types
221
+ ### 1. Types
126
222
 
127
223
  **Purpose**: Declares which data types from `types.json` and maps them to the components, routes, services, helpers and modifiers that consume them. This creates a traceable link between your data layer and your UI implementation.
128
224
 
@@ -147,52 +243,66 @@ The storylang.json file contains seven main sections:
147
243
 
148
244
  ---
149
245
 
150
- ### 3. Components
246
+ ### 2. Routes
151
247
 
152
- **Purpose**: Defines reusable UI components that will be built for the application.
248
+ **Purpose**: Defines the application's routes and their requirements.
153
249
 
154
250
  **Format**:
155
251
 
156
252
  ```json
157
253
  {
158
- "components": [
254
+ "routes": [
159
255
  {
160
- "name": "component-name",
161
- "type": "component-type",
256
+ "name": "route-name", //should match Ember router.js
162
257
  "tracked_vars": [{ "<variableName>": "<dataType>" }],
163
- "inherited_args": [{ "<argumentName>": "<argType>" }],
258
+ "get_vars": [{ "<paramName>": "<dataType>" }],
164
259
  "actions": ["action1", "action2"],
165
- "helpers": ["helper1", "helper2"],
166
- "modifiers": ["modifier1"],
167
- "services": ["service1", "service2"]
260
+ "helpers": ["helper1"],
261
+ "services": ["service1"],
262
+ "components": ["component1", "component2"],
263
+ "types": ["type1", "type2"]
168
264
  }
169
265
  ]
170
266
  }
171
267
  ```
172
268
 
173
- **Built-in Component Types in ember-tribe**:
269
+ ---
174
270
 
175
- - **Layout**: `table`, `figure`, `accordion`, `card`, `list-group`, `navbar`, `nav`, `tab`, `breadcrumb`
176
- - **Interactive**: `button`, `button-group`, `dropdown`, `modal`, `collapse`, `offcanvas`, `pagination`, `popover`, `tooltip`, `swiper-carousel`, `videojs-player`, `howlerjs-player`, `input-field`, `input-group`, `textarea`, `checkbox`, `radio`, `range`, `select`, `multi-select`, `date`, `file-uploader`, `alert`, `badge`, `toast`, `placeholder`, `progress`, `spinner`, `scrollspy`
271
+ ### 3. Helpers
272
+
273
+ **Purpose**: Defines custom template helpers — pure functions used in templates to format, compute or transform data for display.
274
+
275
+ **Format**:
276
+
277
+ ```json
278
+ {
279
+ "helpers": [
280
+ {
281
+ "name": "helper-name",
282
+ "description": "What this helper does",
283
+ "input_args": [{ "<argumentName>": "<dataType>" }],
284
+ "return": "<dataType>"
285
+ }
286
+ ]
287
+ }
288
+ ```
177
289
 
178
290
  **Example**:
179
291
 
180
292
  ```json
181
293
  {
182
- "components": [
294
+ "helpers": [
183
295
  {
184
- "name": "file-summary-card",
185
- "type": "card",
186
- "tracked_vars": [{ "isSelected": "bool" }, { "isExpanded": "bool" }],
187
- "inherited_args": [
188
- { "file": "var" },
189
- { "onEdit": "action" },
190
- { "onDelete": "action" }
191
- ],
192
- "actions": ["toggleSelection", "expandDetails", "editFile", "deleteFile"],
193
- "helpers": ["formatDate", "truncateText"],
194
- "modifiers": ["tooltip"],
195
- "services": ["store", "router"]
296
+ "name": "format-date",
297
+ "description": "Formats a raw ISO date string into a human-readable date",
298
+ "input_args": [{ "isoString": "string" }, { "format": "string" }],
299
+ "return": "string"
300
+ },
301
+ {
302
+ "name": "truncate-text",
303
+ "description": "Truncates a string to a given character limit and appends an ellipsis",
304
+ "input_args": [{ "text": "string" }, { "limit": "int" }],
305
+ "return": "string"
196
306
  }
197
307
  ]
198
308
  }
@@ -200,24 +310,41 @@ The storylang.json file contains seven main sections:
200
310
 
201
311
  ---
202
312
 
203
- ### 4. Routes
313
+ ### 4. Modifiers
204
314
 
205
- **Purpose**: Defines the application's routes and their requirements.
315
+ **Purpose**: Defines custom Ember modifiers functions that directly interact with DOM elements to attach behaviour, third-party libraries or event listeners.
206
316
 
207
317
  **Format**:
208
318
 
209
319
  ```json
210
320
  {
211
- "routes": [
321
+ "modifiers": [
212
322
  {
213
- "name": "route-name", //should match Ember router.js
214
- "tracked_vars": [{ "<variableName>": "<dataType>" }],
215
- "get_vars": [{ "<paramName>": "<dataType>" }],
216
- "actions": ["action1", "action2"],
217
- "helpers": ["helper1"],
218
- "services": ["service1"],
219
- "components": ["component1", "component2"],
220
- "types": ["type1", "type2"]
323
+ "name": "modifier-name",
324
+ "description": "What DOM behaviour this modifier applies",
325
+ "input_args": [{ "<argumentName>": "<dataType>" }],
326
+ "services": ["service1"]
327
+ }
328
+ ]
329
+ }
330
+ ```
331
+
332
+ **Example**:
333
+
334
+ ```json
335
+ {
336
+ "modifiers": [
337
+ {
338
+ "name": "tooltip",
339
+ "description": "Initialises a Bootstrap tooltip on the target element using the provided label",
340
+ "input_args": [{ "label": "string" }, { "placement": "string" }],
341
+ "services": []
342
+ },
343
+ {
344
+ "name": "autofocus",
345
+ "description": "Sets focus on the target element when it is inserted into the DOM",
346
+ "input_args": [],
347
+ "services": []
221
348
  }
222
349
  ]
223
350
  }
@@ -245,18 +372,6 @@ The storylang.json file contains seven main sections:
245
372
  }
246
373
  ```
247
374
 
248
- **Built-in Services in ember-tribe**:
249
-
250
- - `store`: Ember Data store for CRUD operations
251
- - `router`: Ember router service for navigation
252
- - `types`: Automatic model generation from backend tracks
253
- - `bootstrap`: Bootstrap CSS framework with Popper.js
254
- - `papaparse`: CSV parsing library
255
- - `sortablejs`: Drag-and-drop sorting
256
- - `swiperjs`: Touch slider/carousel
257
- - `videojs`: Video player
258
- - `howlerjs`: Audio player
259
-
260
375
  **Example**:
261
376
 
262
377
  ```json
@@ -282,97 +397,47 @@ The storylang.json file contains seven main sections:
282
397
 
283
398
  ---
284
399
 
285
- ### 6. Helpers
286
-
287
- **Purpose**: Defines custom template helpers — pure functions used in templates to format, compute or transform data for display.
288
-
289
- **Format**:
290
-
291
- ```json
292
- {
293
- "helpers": [
294
- {
295
- "name": "helper-name",
296
- "description": "What this helper does",
297
- "args": [{ "<argumentName>": "<dataType>" }],
298
- "return": "<dataType>"
299
- }
300
- ]
301
- }
302
- ```
303
-
304
- **Helper Properties**:
305
-
306
- - `name`: Kebab-case name of the helper
307
- - `description`: Brief description of what the helper computes or transforms
308
- - `args`: Input arguments the helper accepts
309
- - `return`: The data type the helper outputs
310
-
311
- **Example**:
312
-
313
- ```json
314
- {
315
- "helpers": [
316
- {
317
- "name": "format-date",
318
- "description": "Formats a raw ISO date string into a human-readable date",
319
- "args": [{ "isoString": "string" }, { "format": "string" }],
320
- "return": "string"
321
- },
322
- {
323
- "name": "truncate-text",
324
- "description": "Truncates a string to a given character limit and appends an ellipsis",
325
- "args": [{ "text": "string" }, { "limit": "int" }],
326
- "return": "string"
327
- }
328
- ]
329
- }
330
- ```
331
-
332
- ---
333
-
334
- ### 7. Modifiers
400
+ ### 6. Components
335
401
 
336
- **Purpose**: Defines custom Ember modifiers — functions that directly interact with DOM elements to attach behaviour, third-party libraries or event listeners.
402
+ **Purpose**: Defines reusable UI components that will be built for the application.
337
403
 
338
404
  **Format**:
339
405
 
340
406
  ```json
341
407
  {
342
- "modifiers": [
408
+ "components": [
343
409
  {
344
- "name": "modifier-name",
345
- "description": "What DOM behaviour this modifier applies",
346
- "args": [{ "<argumentName>": "<dataType>" }],
347
- "services": ["service1"]
410
+ "name": "component-name",
411
+ "type": "component-type",
412
+ "tracked_vars": [{ "<variableName>": "<dataType>" }],
413
+ "inherited_args": [{ "<argumentName>": "<argType>" }],
414
+ "actions": ["action1", "action2"],
415
+ "helpers": ["helper1", "helper2"],
416
+ "modifiers": ["modifier1"],
417
+ "services": ["service1", "service2"]
348
418
  }
349
419
  ]
350
420
  }
351
421
  ```
352
422
 
353
- **Modifier Properties**:
354
-
355
- - `name`: Kebab-case name of the modifier
356
- - `description`: Brief description of the DOM behaviour it attaches
357
- - `args`: Arguments passed into the modifier from the template
358
- - `services`: Ember services injected if needed
359
-
360
423
  **Example**:
361
424
 
362
425
  ```json
363
426
  {
364
- "modifiers": [
365
- {
366
- "name": "tooltip",
367
- "description": "Initialises a Bootstrap tooltip on the target element using the provided label",
368
- "args": [{ "label": "string" }, { "placement": "string" }],
369
- "services": []
370
- },
427
+ "components": [
371
428
  {
372
- "name": "autofocus",
373
- "description": "Sets focus on the target element when it is inserted into the DOM",
374
- "args": [],
375
- "services": []
429
+ "name": "file-summary-card",
430
+ "type": "card",
431
+ "tracked_vars": [{ "isSelected": "bool" }, { "isExpanded": "bool" }],
432
+ "inherited_args": [
433
+ { "file": "var" },
434
+ { "onEdit": "action" },
435
+ { "onDelete": "action" }
436
+ ],
437
+ "actions": ["toggleSelection", "expandDetails", "editFile", "deleteFile"],
438
+ "helpers": ["formatDate", "truncateText"],
439
+ "modifiers": ["tooltip"],
440
+ "services": ["store", "router"]
376
441
  }
377
442
  ]
378
443
  }
@@ -409,25 +474,6 @@ The storylang.json file contains seven main sections:
409
474
 
410
475
  ---
411
476
 
412
- ### Storylang Best Practices
413
-
414
- **Always begin your thought process with routes → then move repeatable template logic into components → then move repeatable app-wide logic from components and routes to services → then extract reusable template and component functions into helpers → then extract template and component DOM behaviour into modifiers**
415
-
416
- 1. **Start with Routes**: Match route names to user mental models and use consistent naming conventions
417
- 2. **Minimize Route Logic**: Preferably fetch (read) type data in routes and then pass that data to components or services. Other than fetching type data, minimize the use of javascript in routes — Javascript is meant to be in components and services more than in routes
418
- 3. **Route Parameters**: Keep get_vars minimal and meaningful, and load only necessary types for each route
419
- 4. **Component Focus**: Keep components focused on single responsibilities and use descriptive, kebab-case names. Names should indicate which built-in ember-tribe component to use.
420
- 5. **Data Flow**: Receive backend data down from routes (via inherited_args) rather than fetching (reading) in components
421
- 6. **Component Actions**: Non-read functions — create, update, delete — can all happen well at component-level
422
- 7. **Service Integration**: Use services directly in both components and routes for app-wide logic
423
- 8. **Service Architecture**: Keep services stateless when possible and use dependency injection for service composition
424
- 9. **Service Role**: Services interact with both routes and components and store the core logic of the application
425
- 10. **Helpers**: Keep helpers pure and stateless — they should only receive input and return output with no side effects
426
- 11. **Modifiers**: Use modifiers to isolate all direct DOM manipulation and third-party library initialisation from component logic
427
- 12. **Types Mapping**: Populate the `types` section as you define your routes and components — it is your traceability layer between data types and UI
428
-
429
- ---
430
-
431
477
  ## Ember-Tribe Development Guide
432
478
 
433
479
  ### Required File Outputs
@@ -615,66 +661,6 @@ post.destroyRecord(); // => DELETE request
615
661
 
616
662
  ---
617
663
 
618
- ## Component Architecture
619
-
620
- ### Component Structure
621
-
622
- ```javascript
623
- // Component class
624
- import Component from '@glimmer/component';
625
- import { tracked } from '@glimmer/tracking';
626
- import { action } from '@ember/object';
627
- import { service } from '@ember/service';
628
-
629
- export default class FileCardComponent extends Component {
630
- @service store;
631
- @tracked isSelected = false;
632
-
633
- @action
634
- toggleSelection() {
635
- this.isSelected = !this.isSelected;
636
- }
637
- }
638
- ```
639
-
640
- ### Template Patterns
641
-
642
- ```handlebars
643
- <div
644
- class='card {{if this.isSelected "border-primary"}}'
645
- {{on 'click' this.toggleSelection}}
646
- >
647
- <div class='card-body'>
648
- <h5 class='card-title'>{{@file.modules.title}}</h5>
649
- <p class='card-text'>{{@file.modules.description}}</p>
650
- </div>
651
- </div>
652
- ```
653
-
654
- ---
655
-
656
- ## Services Integration
657
-
658
- Make services based on storylang.json service definitions:
659
-
660
- ```javascript
661
- // app/services/visualization-builder.js
662
- import Service from '@ember/service';
663
- import { tracked } from '@glimmer/tracking';
664
- import { service } from '@ember/service';
665
-
666
- export default class VisualizationBuilderService extends Service {
667
- @service store;
668
- @tracked supportedTypes = ['network', 'tree', 'sankey'];
669
-
670
- buildVisualization(files, type, config) {
671
- // Service logic implementation
672
- }
673
- }
674
- ```
675
-
676
- ---
677
-
678
664
  ## Route Generation
679
665
 
680
666
  ### Route Creation
@@ -936,9 +922,69 @@ export default class CartContentsComponent extends Component {
936
922
 
937
923
  ---
938
924
 
939
- ## Code Generation Process
925
+ ## Services Integration
940
926
 
941
- ### File Upload Javascript Example
927
+ Make services based on storylang.json service definitions:
928
+
929
+ ```javascript
930
+ // app/services/visualization-builder.js
931
+ import Service from '@ember/service';
932
+ import { tracked } from '@glimmer/tracking';
933
+ import { service } from '@ember/service';
934
+
935
+ export default class VisualizationBuilderService extends Service {
936
+ @service store;
937
+ @tracked supportedTypes = ['network', 'tree', 'sankey'];
938
+
939
+ buildVisualization(files, type, config) {
940
+ // Service logic implementation
941
+ }
942
+ }
943
+ ```
944
+
945
+ ---
946
+
947
+ ## Component Architecture
948
+
949
+ ### Component Structure
950
+
951
+ ```javascript
952
+ // Component class
953
+ import Component from '@glimmer/component';
954
+ import { tracked } from '@glimmer/tracking';
955
+ import { action } from '@ember/object';
956
+ import { service } from '@ember/service';
957
+
958
+ export default class FileCardComponent extends Component {
959
+ @service store;
960
+ @tracked isSelected = false;
961
+
962
+ @action
963
+ toggleSelection() {
964
+ this.isSelected = !this.isSelected;
965
+ }
966
+ }
967
+ ```
968
+
969
+ ### Template Patterns
970
+
971
+ ```handlebars
972
+ <div
973
+ class='card {{if this.isSelected "border-primary"}}'
974
+ {{on 'click' this.toggleSelection}}
975
+ >
976
+ <div class='card-body'>
977
+ <h5 class='card-title'>{{@file.modules.title}}</h5>
978
+ <p class='card-text'>{{@file.modules.description}}</p>
979
+ </div>
980
+ </div>
981
+ ```
982
+
983
+ ---
984
+
985
+ ## Forms and Input Fields
986
+
987
+ ### File upload javascript example
942
988
 
943
989
  ```javascript
944
990
  import ENV from '<your-application-name>/config/environment';
@@ -968,6 +1014,153 @@ async uploadFile(file) {
968
1014
  }
969
1015
  ```
970
1016
 
1017
+ ### Input and Textarea fields
1018
+
1019
+ Use Ember's built-in `<Input>` component instead of a raw `<input>` tag — it automatically updates bound state via `@value`.
1020
+
1021
+ ```handlebars
1022
+ <div class="mb-3">
1023
+ <label for="input-name" class="form-label">Name:</label>
1024
+ <Input
1025
+ id="input-name"
1026
+ class="form-control"
1027
+ @type="text"
1028
+ @value={{this.name}}
1029
+ disabled={{this.isReadOnly}}
1030
+ maxlength="50"
1031
+ placeholder="Enter your name"
1032
+ />
1033
+ </div>
1034
+ ```
1035
+
1036
+ ```javascript
1037
+ import Component from '@glimmer/component';
1038
+ import { tracked } from '@glimmer/tracking';
1039
+
1040
+ export default class ExampleComponent extends Component {
1041
+ @tracked name = '';
1042
+ @tracked isReadOnly = false;
1043
+ }
1044
+ ```
1045
+
1046
+ ```handlebars
1047
+ <div class="form-check mb-3">
1048
+ <Input
1049
+ id="admin-checkbox"
1050
+ class="form-check-input"
1051
+ @type="checkbox"
1052
+ @checked={{this.isAdmin}}
1053
+ {{on "input" this.validateRole}}
1054
+ />
1055
+ <label for="admin-checkbox" class="form-check-label">Is Admin?</label>
1056
+ </div>
1057
+ ```
1058
+
1059
+ ```handlebars
1060
+ <div class="mb-3">
1061
+ <label for="user-comment" class="form-label">Comment:</label>
1062
+ <Textarea
1063
+ id="user-comment"
1064
+ class="form-control"
1065
+ @value={{this.userComment}}
1066
+ rows="6"
1067
+ />
1068
+ </div>
1069
+ ```
1070
+
1071
+ **Key rules for `<Input>` and `<Textarea>`:**
1072
+ - `@value`, `@type`, and `@checked` must be passed as **arguments** (with `@`).
1073
+ - Use the `{{on}}` modifier for event handling (e.g. `{{on "input" this.handler}}`).
1074
+ - Bootstrap styles `form-control` correctly when `disabled` is present
1075
+
1076
+ ### ember-power-select example
1077
+
1078
+ `ember-power-select` is the recommended way to implement searchable, single, and multi-select dropdowns in ember-tribe. It is pre-installed and works alongside Bootstrap 5.x. Use it wherever a native `<select>` would be insufficient — e.g. when you need search/filter, async options, or multi-select.
1079
+
1080
+ **Single select (Bootstrap-compatible wrapper):**
1081
+
1082
+ ```handlebars
1083
+ <div class="mb-3">
1084
+ <label class="form-label">Assign Category:</label>
1085
+ <div class="form-control p-0 border-0">
1086
+ <PowerSelect
1087
+ @options={{this.categories}}
1088
+ @selected={{this.selectedCategory}}
1089
+ @onChange={{this.handleCategoryChange}}
1090
+ @placeholder="Select a category"
1091
+ as |category|
1092
+ >
1093
+ {{category.name}}
1094
+ </PowerSelect>
1095
+ </div>
1096
+ </div>
1097
+ ```
1098
+
1099
+ ```javascript
1100
+ import Component from '@glimmer/component';
1101
+ import { tracked } from '@glimmer/tracking';
1102
+ import { action } from '@ember/object';
1103
+
1104
+ export default class ExampleComponent extends Component {
1105
+ @tracked selectedCategory = null;
1106
+
1107
+ categories = [
1108
+ { id: 1, name: 'Design' },
1109
+ { id: 2, name: 'Engineering' },
1110
+ { id: 3, name: 'Marketing' },
1111
+ ];
1112
+
1113
+ @action
1114
+ handleCategoryChange(category) {
1115
+ this.selectedCategory = category;
1116
+ }
1117
+ }
1118
+ ```
1119
+
1120
+ **Multi-select variant:**
1121
+
1122
+ ```handlebars
1123
+ <div class="mb-3">
1124
+ <label class="form-label">Assign Tags:</label>
1125
+ <div class="form-control p-0 border-0">
1126
+ <PowerSelectMultiple
1127
+ @options={{this.availableTags}}
1128
+ @selected={{this.selectedTags}}
1129
+ @onChange={{this.handleTagsChange}}
1130
+ @placeholder="Select tags"
1131
+ as |tag|
1132
+ >
1133
+ {{tag.label}}
1134
+ </PowerSelectMultiple>
1135
+ </div>
1136
+ </div>
1137
+ ```
1138
+
1139
+ **Async options loaded from the store:**
1140
+
1141
+ ```handlebars
1142
+ <div class="mb-3">
1143
+ <label class="form-label">Select Project:</label>
1144
+ <div class="form-control p-0 border-0">
1145
+ <PowerSelect
1146
+ @options={{this.projects}}
1147
+ @selected={{this.selectedProject}}
1148
+ @onChange={{this.handleProjectChange}}
1149
+ @searchField="name"
1150
+ @placeholder="Search projects..."
1151
+ as |project|
1152
+ >
1153
+ {{project.modules.name}}
1154
+ </PowerSelect>
1155
+ </div>
1156
+ </div>
1157
+ ```
1158
+
1159
+ **Key rules for `<PowerSelect>`:**
1160
+ - `@options`, `@selected`, and `@onChange` are always required arguments.
1161
+ - Use `@searchField` to specify which object property drives the built-in search filter.
1162
+ - For multi-select, use `<PowerSelectMultiple>` — the `@onChange` callback receives the full updated array, so assign it directly to your tracked property.
1163
+
971
1164
  ---
972
1165
 
973
1166
  ## Deploying to Junction (Self-Hosted)
@@ -985,19 +1178,6 @@ You can then upload the `dist/` folder to [Junction (open source)](http://localh
985
1178
 
986
1179
  ---
987
1180
 
988
- ## Best Practices
989
-
990
- 1. **Module Access**: Remember to use `modules.field_name` for backend fields
991
- 2. **npm packages vs ember addons**: Prioritize npm packages over ember addons for better compatibility, when both are offering similar functionality
992
- 3. **Minimal Controllers**: Logic should ideally reside in components and services
993
- 4. **Bootstrap 5.x Foundation**: Responsive, accessible design system
994
- 5. **Use FontAwesome 6.x**: Comprehensive icon library
995
- 6. **Animations**: If required, use animate.css for enhanced user experience. Prefer subtle animations (fadeIn, slideIn). Avoid overwhelming users with excessive animation
996
- 7. **Access Cache**: Leverage EmberData caching with `peekRecord`
997
- 8. **Avoid array manipulations of backend data**: Use backend filtering over frontend array manipulation
998
-
999
- ---
1000
-
1001
1181
  # License
1002
1182
 
1003
1183
  This project is licensed under the [GNU GPL v3 License](LICENSE.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-tribe",
3
- "version": "2.6.7",
3
+ "version": "2.6.8",
4
4
  "description": "The default blueprint for using Tribe API and Junction within EmberJS.",
5
5
  "keywords": [
6
6
  "ember-addon"