create-flowmo 1.2.1 → 1.2.2

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/index.js CHANGED
@@ -88,6 +88,7 @@ async function init() {
88
88
  // Copy starter template files (CSS, starter screen, data, logic)
89
89
  const templateDir = path.join(__dirname, 'template');
90
90
  await fs.copy(path.join(templateDir, 'theme'), path.join(projectPath, 'theme'));
91
+ await fs.copy(path.join(templateDir, 'scripts'), path.join(projectPath, 'scripts'));
91
92
  await fs.copy(path.join(templateDir, 'screens'), path.join(projectPath, 'screens'));
92
93
  await fs.copy(path.join(templateDir, 'data'), path.join(projectPath, 'data'));
93
94
  await fs.copy(path.join(templateDir, 'logic'), path.join(projectPath, 'logic'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-flowmo",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Scaffold an OutSystems-Lite project with screens, data, logic, and built-in agent skills",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -360,19 +360,108 @@ Some patterns expose CSS custom properties for fine-tuning. Set these on the pat
360
360
  | Rating | `--rating-size: 16px` |
361
361
  | Scrollable Area | `--scrollable-area-width`, `--scrollable-area-height` |
362
362
 
363
+ ## Responsive & Device Classes
364
+
365
+ OutSystems uses a **JavaScript-based** responsive system, not CSS media queries. A runtime script detects the viewport size and applies device + orientation classes to `<body>`. All OSUI responsive CSS rules are scoped to these body classes.
366
+
367
+ ### Body Classes
368
+
369
+ | Viewport width | Body class | Orientation class |
370
+ |----------------|-----------|-------------------|
371
+ | `< 768px` | `phone` | `portrait` (w ≤ h) or `landscape` (w > h) |
372
+ | `768px – 1024px` | `tablet` | `portrait` or `landscape` |
373
+ | `> 1024px` | `desktop` | `landscape` (typically) |
374
+
375
+ In the real OutSystems platform, this is handled by the platform runtime. For static `.visual.html` files, include the **`device-detect.js`** script at the bottom of `<body>` — it replicates the same behavior:
376
+
377
+ ```html
378
+ <script src="../scripts/device-detect.js"></script>
379
+ ```
380
+
381
+ This script runs on load AND on resize, so the body class updates when the browser window changes size.
382
+
383
+ ### Column Break Behavior
384
+
385
+ Columns patterns (`columns2` through `columns6`, `columns-small-left`, etc.) stay side-by-side on desktop. On tablet and phone, you control how they collapse using **break classes**:
386
+
387
+ | Break class | Effect on the target breakpoint |
388
+ |-------------|--------------------------------|
389
+ | *(none)* | Columns keep their desktop proportions — no stacking |
390
+ | `{device}-break-all` | **All** columns stack to 100% width (full-width rows) |
391
+ | `{device}-break-first` | **First** column breaks to 100% width; remaining stay side-by-side |
392
+ | `{device}-break-last` | **Last** column breaks to 100% width; preceding stay side-by-side |
393
+ | `{device}-break-middle` | Middle columns break — behavior varies by column count (see below) |
394
+
395
+ Where `{device}` is `tablet` or `phone`. You can combine both independently:
396
+
397
+ ```html
398
+ <!-- On tablet: first column breaks. On phone: all columns stack. -->
399
+ <div class="columns columns3 gutter-base tablet-break-first phone-break-all">
400
+ <div class="columns-item">Sidebar</div>
401
+ <div class="columns-item">Main</div>
402
+ <div class="columns-item">Aside</div>
403
+ </div>
404
+ ```
405
+
406
+ #### `break-middle` Details
407
+
408
+ `break-middle` is a halfway collapse — it reduces the column count without going to full-width:
409
+
410
+ | Column type | `break-middle` result |
411
+ |-------------|----------------------|
412
+ | `columns2` | All items → 100% width (same as break-all) |
413
+ | `columns3` | Last item → 100% width; first two stay side-by-side |
414
+ | `columns4` | All items → 50% width (2×2 grid) |
415
+ | `columns5` / `columns6` | First 3 items → 33.333% width (3-col row); rest flow below |
416
+ | `columns-small-left`, `-medium-left`, `-small-right`, `-medium-right` | All items → 100% width |
417
+
418
+ ### Gutter Classes
419
+
420
+ The gutter controls spacing between columns. It works with break classes — when columns stack, the gutter becomes vertical margin:
421
+
422
+ | Gutter | Class |
423
+ |--------|-------|
424
+ | None | `gutter-none` |
425
+ | XS (4px) | `gutter-xs` |
426
+ | S (8px) | `gutter-s` |
427
+ | Base (16px) | `gutter-base` |
428
+ | M (24px) | `gutter-m` |
429
+ | L (32px) | `gutter-l` |
430
+ | XL (40px) | `gutter-xl` |
431
+ | XXL (48px) | `gutter-xxl` |
432
+
433
+ ### Display On Device
434
+
435
+ Show/hide entire elements per breakpoint:
436
+
437
+ ```html
438
+ <div class="display-on-device-desktop">Desktop only content</div>
439
+ <div class="display-on-device-tablet">Tablet only content</div>
440
+ <div class="display-on-device-phone">Phone only content</div>
441
+ ```
442
+
443
+ These require the correct body class to work — so `device-detect.js` is required for static previews.
444
+
363
445
  ## Theme Customization
364
446
 
365
- Every project ships three CSS files, loaded in this order:
447
+ Every project ships three CSS files and one JS file, loaded in this order:
366
448
 
367
449
  1. **`outsystems-ui.css`** — the OSUI framework (patterns, utilities, layout). Never edit this.
368
450
  2. **`grid.css`** — platform grid definitions (`.ThemeGrid_Container` max-width, `.ThemeGrid_Width*` columns, `.ThemeGrid_MarginGutter` spacing, `.active-screen` scroll model). Normally injected by OutSystems at runtime — we provide it statically. Never edit this.
369
451
  3. **`theme.css`** — project-specific brand tokens and custom styles. This is the only file you should edit.
452
+ 4. **`device-detect.js`** (in `scripts/`) — viewport detection script that applies `phone`/`tablet`/`desktop` + `portrait`/`landscape` classes to `<body>`. Required for responsive column breaks and `display-on-device-*` classes. Never edit this.
370
453
 
371
- All three `<link>` tags must be present in `<head>`:
454
+ All three `<link>` tags must be present in `<head>`, and the script at the bottom of `<body>`:
372
455
  ```html
373
- <link rel="stylesheet" href="../theme/outsystems-ui.css" />
374
- <link rel="stylesheet" href="../theme/grid.css" />
375
- <link rel="stylesheet" href="../theme/theme.css" />
456
+ <head>
457
+ <link rel="stylesheet" href="../theme/outsystems-ui.css" />
458
+ <link rel="stylesheet" href="../theme/grid.css" />
459
+ <link rel="stylesheet" href="../theme/theme.css" />
460
+ </head>
461
+ <body>
462
+ <!-- ... page content ... -->
463
+ <script src="../scripts/device-detect.js"></script>
464
+ </body>
376
465
  ```
377
466
 
378
467
  ### What theme.css MUST contain
@@ -442,15 +531,22 @@ Follow this checklist when creating or editing a screen. Do not skip steps.
442
531
  2. No inline `style=""` attributes anywhere
443
532
  3. All classes are OSUI utilities OR custom classes defined in `theme.css`
444
533
  4. All three CSS stylesheets linked in `<head>`: `outsystems-ui.css`, `grid.css`, `theme.css` (in that order)
445
- 5. If Font Awesome icons are used, the FA CDN `<link>` is in `<head>`
446
- 6. No `@media` queries or custom breakpoints
447
- 7. Scroll model and grid are handled by `grid.css` (not duplicated in `theme.css`)
448
- 8. **Text readability** for every text element, confirm the text color contrasts with its background:
534
+ 5. `device-detect.js` script tag present at end of `<body>`
535
+ 6. If Font Awesome icons are used, the FA CDN `<link>` is in `<head>`
536
+ 7. No `@media` queries or custom breakpoints
537
+ 8. Scroll model and grid are handled by `grid.css` (not duplicated in `theme.css`)
538
+ 9. **Text readability** — for every text element, confirm the text color contrasts with its background:
449
539
  - Dark backgrounds (`.background-primary`, `.background-neutral-10`, navy/dark sections) → use light text (`.text-neutral-0` or white custom class)
450
540
  - Light backgrounds (`.background-neutral-0`, white sections) → use dark text (`.text-neutral-10` or default)
451
541
  - **Header and menu links are especially prone** — if the header has a dark background, menu links MUST use a light text class. OSUI link defaults are the primary color, which may be invisible on a dark header.
452
542
  - Buttons: check that button text contrasts with the button background (`.btn` defaults to white text — don't add `.text-neutral-0` on a white button)
453
- 9. If any check fails, fix and re-check before continuing
543
+ 10. **Responsive columns** for every `.columns*` pattern, verify the break behavior:
544
+ - Every multi-column layout SHOULD have a `phone-break-*` class. Without one, columns stay side-by-side on phone, which is almost always wrong.
545
+ - Choose the right break: `phone-break-all` (stack everything) is the safe default. Use `phone-break-first`/`-last` when one column should stay full-width while others share a row.
546
+ - For tablet, add `tablet-break-*` only if the column count is 4+ or if side-by-side is too cramped at 768px.
547
+ - `break-middle` is the right choice for `columns4`–`columns6` on tablet — it goes to a 2- or 3-column grid instead of full-width stacking.
548
+ - Verify gutter class is present (`gutter-base` is the safe default).
549
+ 11. If any check fails, fix and re-check before continuing
454
550
  - [ ] Step 3: **Install dependencies** — if `node_modules/` does not exist, run `npm install`
455
551
  - [ ] Step 4: **Start the dev server** — run `npm run dev` to serve the project at `http://localhost:5173/`
456
552
  - [ ] Step 5: **Visual verification** — open the screen URL in the browser and check:
@@ -470,7 +566,8 @@ Follow this checklist when creating or editing a screen. Do not skip steps.
470
566
  - **Font Awesome is not bundled** — If using `<i class="fa fa-exchange">` style icons, add the FA 4.7 CDN link to `<head>` or the icons will be invisible (0×0 size).
471
567
  - OutSystems pattern previews render inside iframes — CSS resolves against the OSUI framework, not browser defaults. Your `.visual.html` must link the OSUI stylesheet.
472
568
  - **Never mix** inline `style=""` attributes with utility classes. Always prefer utility classes.
473
- - `.columns*` patterns auto-stack on mobile breakpoints. Do NOT add custom `@media` queries to override this behavior.
569
+ - `.columns*` patterns auto-stack on mobile breakpoints **only if a break class is applied** (e.g. `phone-break-all`). Without a break class, columns stay side-by-side on all viewports. Do NOT add custom `@media` queries use the break classes instead.
570
+ - **`device-detect.js` is required** — responsive column breaks and `display-on-device-*` classes are scoped to body classes (`phone`, `tablet`, `desktop`). Without the script, they have no effect in static previews.
474
571
  - Button loading state is purely CSS (`.btn-loading` + spinner element), not a JavaScript toggle.
475
572
  - Use `{{content}}` placeholders in component templates to indicate where nested child widgets go.
476
573
  - Always generate BOTH the `.visual.html` AND corresponding `theme.css` styles together. A screen without proper theme styles will look broken.
@@ -8,7 +8,7 @@
8
8
  <link rel="stylesheet" href="../theme/grid.css" />
9
9
  <link rel="stylesheet" href="../theme/theme.css" />
10
10
  </head>
11
- <body class="desktop">
11
+ <body>
12
12
  <!--
13
13
  LayoutBase — Full-width sections, content-first.
14
14
  Best for: landing pages, marketing pages, public-facing screens.
@@ -105,5 +105,6 @@
105
105
  </div>
106
106
  </div>
107
107
  </div>
108
+ <script src="../scripts/device-detect.js"></script>
108
109
  </body>
109
110
  </html>
@@ -8,7 +8,7 @@
8
8
  <link rel="stylesheet" href="../theme/grid.css" />
9
9
  <link rel="stylesheet" href="../theme/theme.css" />
10
10
  </head>
11
- <body class="desktop">
11
+ <body>
12
12
  <!--
13
13
  LayoutBlank — No header, no footer, no navigation.
14
14
  Best for: login pages, error pages, splash screens, or any screen
@@ -27,5 +27,6 @@
27
27
 
28
28
  </div>
29
29
  </div>
30
+ <script src="../scripts/device-detect.js"></script>
30
31
  </body>
31
32
  </html>
@@ -8,7 +8,7 @@
8
8
  <link rel="stylesheet" href="../theme/grid.css" />
9
9
  <link rel="stylesheet" href="../theme/theme.css" />
10
10
  </head>
11
- <body class="desktop">
11
+ <body>
12
12
  <!--
13
13
  LayoutSideMenu — Vertical navigation in a left sidebar.
14
14
  Best for: backoffice/admin apps with many pages or deep navigation.
@@ -114,5 +114,6 @@
114
114
  </div>
115
115
  </div>
116
116
  </div>
117
+ <script src="../scripts/device-detect.js"></script>
117
118
  </body>
118
119
  </html>
@@ -8,7 +8,7 @@
8
8
  <link rel="stylesheet" href="../theme/grid.css" />
9
9
  <link rel="stylesheet" href="../theme/theme.css" />
10
10
  </head>
11
- <body class="desktop">
11
+ <body>
12
12
  <!--
13
13
  LayoutTopMenu — Horizontal navigation bar at the top.
14
14
  Best for: web apps with few top-level pages (3–6 menu items).
@@ -97,5 +97,6 @@
97
97
  </div>
98
98
  </div>
99
99
  </div>
100
+ <script src="../scripts/device-detect.js"></script>
100
101
  </body>
101
102
  </html>
@@ -11,7 +11,7 @@ Notation: `tag.class1.class2` for elements, `[Block.Name]` for OutSystems block
11
11
  ### Columns 2
12
12
 
13
13
  ```html
14
- <div class="columns columns2 gutter-base">
14
+ <div class="columns columns2 gutter-base phone-break-all">
15
15
  <div class="columns-item">Column 1</div>
16
16
  <div class="columns-item">Column 2</div>
17
17
  </div>
@@ -20,7 +20,7 @@ Notation: `tag.class1.class2` for elements, `[Block.Name]` for OutSystems block
20
20
  ### Columns 3
21
21
 
22
22
  ```html
23
- <div class="columns columns3 gutter-base">
23
+ <div class="columns columns3 gutter-base phone-break-all">
24
24
  <div class="columns-item">Column 1</div>
25
25
  <div class="columns-item">Column 2</div>
26
26
  <div class="columns-item">Column 3</div>
@@ -30,7 +30,7 @@ Notation: `tag.class1.class2` for elements, `[Block.Name]` for OutSystems block
30
30
  ### Columns 4
31
31
 
32
32
  ```html
33
- <div class="columns columns4 gutter-base">
33
+ <div class="columns columns4 gutter-base tablet-break-middle phone-break-all">
34
34
  <div class="columns-item">Column 1</div>
35
35
  <div class="columns-item">Column 2</div>
36
36
  <div class="columns-item">Column 3</div>
@@ -41,7 +41,7 @@ Notation: `tag.class1.class2` for elements, `[Block.Name]` for OutSystems block
41
41
  ### Columns 5
42
42
 
43
43
  ```html
44
- <div class="columns columns5 gutter-base">
44
+ <div class="columns columns5 gutter-base tablet-break-middle phone-break-all">
45
45
  <div class="columns-item">...</div>
46
46
  <!-- 5 columns-item -->
47
47
  </div>
@@ -50,7 +50,7 @@ Notation: `tag.class1.class2` for elements, `[Block.Name]` for OutSystems block
50
50
  ### Columns 6
51
51
 
52
52
  ```html
53
- <div class="columns columns6 gutter-base">
53
+ <div class="columns columns6 gutter-base tablet-break-middle phone-break-all">
54
54
  <div class="columns-item">...</div>
55
55
  <!-- 6 columns-item -->
56
56
  </div>
@@ -59,7 +59,7 @@ Notation: `tag.class1.class2` for elements, `[Block.Name]` for OutSystems block
59
59
  ### Columns Medium Left
60
60
 
61
61
  ```html
62
- <div class="columns columns-medium-left gutter-base">
62
+ <div class="columns columns-medium-left gutter-base phone-break-all">
63
63
  <div class="columns-item">Wider left</div>
64
64
  <div class="columns-item">Narrower right</div>
65
65
  </div>
@@ -68,7 +68,7 @@ Notation: `tag.class1.class2` for elements, `[Block.Name]` for OutSystems block
68
68
  ### Columns Medium Right
69
69
 
70
70
  ```html
71
- <div class="columns columns-medium-right gutter-base">
71
+ <div class="columns columns-medium-right gutter-base phone-break-all">
72
72
  <div class="columns-item">Narrower left</div>
73
73
  <div class="columns-item">Wider right</div>
74
74
  </div>
@@ -77,7 +77,7 @@ Notation: `tag.class1.class2` for elements, `[Block.Name]` for OutSystems block
77
77
  ### Columns Small Left
78
78
 
79
79
  ```html
80
- <div class="columns columns-small-left gutter-base">
80
+ <div class="columns columns-small-left gutter-base phone-break-all">
81
81
  <div class="columns-item">Small left</div>
82
82
  <div class="columns-item">Large right</div>
83
83
  </div>
@@ -86,12 +86,40 @@ Notation: `tag.class1.class2` for elements, `[Block.Name]` for OutSystems block
86
86
  ### Columns Small Right
87
87
 
88
88
  ```html
89
- <div class="columns columns-small-right gutter-base">
89
+ <div class="columns columns-small-right gutter-base phone-break-all">
90
90
  <div class="columns-item">Large left</div>
91
91
  <div class="columns-item">Small right</div>
92
92
  </div>
93
93
  ```
94
94
 
95
+ ### Column Break Variants
96
+
97
+ Combine `tablet-break-*` and `phone-break-*` independently:
98
+
99
+ ```html
100
+ <!-- First column breaks on phone, all stay on tablet -->
101
+ <div class="columns columns3 gutter-base phone-break-first">
102
+ <div class="columns-item">Sidebar (full-width on phone)</div>
103
+ <div class="columns-item">Main</div>
104
+ <div class="columns-item">Aside</div>
105
+ </div>
106
+
107
+ <!-- 4-column grid: 2×2 on tablet, full-stack on phone -->
108
+ <div class="columns columns4 gutter-base tablet-break-middle phone-break-all">
109
+ <div class="columns-item">Card 1</div>
110
+ <div class="columns-item">Card 2</div>
111
+ <div class="columns-item">Card 3</div>
112
+ <div class="columns-item">Card 4</div>
113
+ </div>
114
+
115
+ <!-- Last column breaks on both tablet and phone -->
116
+ <div class="columns columns3 gutter-m tablet-break-last phone-break-all">
117
+ <div class="columns-item">Main</div>
118
+ <div class="columns-item">Secondary</div>
119
+ <div class="columns-item">Full-width footer row</div>
120
+ </div>
121
+ ```
122
+
95
123
  ### Display On Device
96
124
 
97
125
  Show/hide content per breakpoint.
@@ -8,7 +8,7 @@
8
8
  <link rel="stylesheet" href="../theme/grid.css">
9
9
  <link rel="stylesheet" href="../theme/theme.css">
10
10
  </head>
11
- <body class="desktop">
11
+ <body>
12
12
  <div class="active-screen">
13
13
  <div data-block="Layouts.LayoutTopMenu" class="layout layout-top fixed-header">
14
14
  <div class="main">
@@ -68,5 +68,6 @@
68
68
  </div>
69
69
  </div>
70
70
  </div>
71
+ <script src="../scripts/device-detect.js"></script>
71
72
  </body>
72
73
  </html>
@@ -0,0 +1,40 @@
1
+ /* ── OutSystems Device Class Detection ────────────────
2
+ In the real OutSystems platform, a runtime script detects
3
+ the viewport size and applies device + orientation classes
4
+ to <body>. Since we render static .visual.html files
5
+ outside the platform, this script replicates that behavior.
6
+
7
+ Breakpoints (matches OS runtime):
8
+ phone: width < 768
9
+ tablet: 768 ≤ width ≤ 1024
10
+ desktop: width > 1024
11
+
12
+ Orientation:
13
+ landscape: width > height
14
+ portrait: width ≤ height
15
+
16
+ Usage: add <script src="../theme/device-detect.js"></script>
17
+ at the end of <body>, AFTER the HTML content.
18
+ ──────────────────────────────────────────────────────── */
19
+ (function () {
20
+ var PHONE = 'phone';
21
+ var TABLET = 'tablet';
22
+ var DESKTOP = 'desktop';
23
+ var PORTRAIT = 'portrait';
24
+ var LANDSCAPE = 'landscape';
25
+ var ALL_CLASSES = [PHONE, TABLET, DESKTOP, PORTRAIT, LANDSCAPE];
26
+
27
+ function applyDeviceClasses() {
28
+ var w = window.innerWidth || document.documentElement.clientWidth;
29
+ var h = window.innerHeight || document.documentElement.clientHeight;
30
+ var device = w < 768 ? PHONE : w <= 1024 ? TABLET : DESKTOP;
31
+ var orientation = w > h ? LANDSCAPE : PORTRAIT;
32
+ var body = document.body;
33
+
34
+ ALL_CLASSES.forEach(function (c) { body.classList.remove(c); });
35
+ body.classList.add(device, orientation);
36
+ }
37
+
38
+ applyDeviceClasses();
39
+ window.addEventListener('resize', applyDeviceClasses);
40
+ })();