@fluid-app/fluid-cli-theme-dev 0.1.19 → 0.1.21

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.
@@ -0,0 +1,118 @@
1
+ # Setting types — the engine contract
2
+
3
+ > Part of the `themes-review` skill. See [`../SKILL.md`](../SKILL.md) for the review workflow, severity ladder, and validator rules.
4
+
5
+ ## Contents
6
+
7
+ - Input
8
+ - Number & selection
9
+ - Visual & media
10
+ - Layout
11
+ - Organization
12
+ - Resource — single
13
+ - Resource — list (multiple)
14
+ - Common type mistakes — find and fix
15
+
16
+
17
+ These are the canonical setting types. **Any `type:` value not in this list is rejected by the validator** (`fluid theme lint --json`).
18
+
19
+ ### Input
20
+
21
+ | `type` | Stores | Notes |
22
+ | --------------- | ----------- | --------------------------------------------------------- |
23
+ | `text` | string | Single-line. |
24
+ | `plaintext` | string | Single-line, no formatting allowed. |
25
+ | `textarea` | string | Multi-line, no formatting. |
26
+ | `richtext` | HTML string | WYSIWYG. **Render with `{{ value }}` — do not `escape`.** |
27
+ | `rich_text` | HTML string | Alias for `richtext`. Prefer `richtext`. |
28
+ | `html` | HTML string | Raw HTML editor. Same render rule as `richtext`. |
29
+ | `html_textarea` | HTML string | Multi-line raw HTML. Same render rule. |
30
+ | `url` | string | Validated URL input. |
31
+
32
+ ### Number & selection
33
+
34
+ | `type` | Required extras | Notes |
35
+ | ---------- | ------------------------------------- | --------------------------------------------------------------- |
36
+ | `range` | `min`, `max`, `step` | Slider. Optional `unit`. |
37
+ | `number` | — | Free numeric input (no slider). Prefer `range` when bounded. |
38
+ | `select` | `options` array of `{ value, label }` | Dropdown. |
39
+ | `radio` | `options` array of `{ value, label }` | Radio group. |
40
+ | `checkbox` | — | Boolean. **Always set `default:`** so the value is never `nil`. |
41
+
42
+ ### Visual & media
43
+
44
+ | `type` | Notes |
45
+ | ------------------ | ----------------------------------------------------------------- |
46
+ | `color` | Single color picker. |
47
+ | `color_background` | Same as `color`, semantic name for fills. |
48
+ | `font` | Font family. |
49
+ | `font_picker` | Font family with Google Fonts + system fonts. |
50
+ | `image` | Single image. |
51
+ | `image_picker` | Single image. Prefer `image_picker` in new code (clearer intent). |
52
+ | `video_picker` | Single video. |
53
+ | `media_picker` | Image **or** video — use when both are acceptable. |
54
+ | `text_alignment` | left / center / right control. |
55
+
56
+ ### Layout
57
+
58
+ | `type` | Notes |
59
+ | ------------------ | ------------------------------- |
60
+ | `media_fit` | cover / contain / fill control. |
61
+ | `corner_radius` | Border-radius preset. |
62
+ | `padding` | Padding scale picker. |
63
+ | `border` | Border preset. |
64
+ | `gradient_overlay` | Gradient editor for overlays. |
65
+
66
+ ### Organization
67
+
68
+ | `type` | Notes |
69
+ | -------- | ----------------------------------------------------- |
70
+ | `header` | Settings-panel divider. No `id`. Requires `content:`. |
71
+
72
+ ### Resource — single
73
+
74
+ These pick **one** resource. Settings hold the resource object/ID.
75
+
76
+ `product`, `collection`, `category`, `blog`, `post`, `enrollment`, `enrollment_pack`, `variant`, `forms`, `media`, `link_list`
77
+
78
+ > **Naming oddity:** `products`, `collections`, `categories`, `posts`, `enrollments` also exist in the _single_ bucket of the canonical list. Read this as **legacy aliases**. Always pair "I want multiple resources" with the `_list` types below — that is the unambiguous, list-shaped contract.
79
+
80
+ ### Resource — list (multiple)
81
+
82
+ These pick **many** resources, stored as arrays. Always require `limit:`.
83
+
84
+ `product_list`, `products_list`, `collection_list`, `collections_list`, `category_list`, `categories_list`, `posts_list`, `enrollment_list`, `enrollments_list`, `blog_list`, `blogs_list`, `post_list`, `enrollment_packs_list`
85
+
86
+ **Canonical names to prefer in new code:**
87
+
88
+ | Resource | Use |
89
+ | ----------------------- | ----------------------- |
90
+ | Products (many) | `product_list` |
91
+ | Collections (many) | `collection_list` |
92
+ | Categories (many) | `category_list` |
93
+ | Posts (many) | `posts_list` |
94
+ | Enrollments (many) | `enrollment_list` |
95
+ | Enrollment packs (many) | `enrollment_packs_list` |
96
+ | Blogs (many) | `blog_list` |
97
+
98
+ The `*s_list` variants (`products_list`, `collections_list`, etc.) exist but are duplicative — flag them as a `nit` and suggest the canonical `*_list` form.
99
+
100
+ ### Common type mistakes — find and fix
101
+
102
+ | You see | What you do |
103
+ | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
104
+ | `type: "text_area"` | **`blocker`.** Use `textarea` (one word). |
105
+ | `type: "checkBox"` / `"image_pick"` | **`blocker`.** Mistyped — replace with the exact value from the lists above. |
106
+ | `type: "product_list"` without `"limit":` | **`should`** — the field saves but has no defined cap. Always set `limit:`. |
107
+ | `type: "range"` without `min`/`max`/`step` | **`blocker`.** Slider UI breaks. |
108
+ | `type: "select"` or `"radio"` without `options:` | **`blocker`.** Empty dropdown / radio group. |
109
+ | `type: "checkbox"` without `default:` | **`should`.** Truthiness is ambiguous on first render. Set `default: false` (or `true`). |
110
+ | `type: "richtext"` rendered as `{{ value | escape }}` | **`blocker`.** Double-escapes HTML — users see `<p>`. Render raw: `{{ value }}`. |
111
+ | Setting missing `id` / duplicate `id` | **`blocker`.** The validator will reject. |
112
+ | Block missing `type` or `name` | **`blocker`.** Validator rejects. (`name` may be omitted only for `@app`, `@theme`, or named-block refs.) |
113
+ | `"settings": { ... }` inside a block (object, not array) | **`blocker`.** Validator rejects — must be an array. |
114
+ | `{% section 'foo' %}` with no `sections/foo/index.liquid` | **`blocker`.** Validator rejects. |
115
+ | 2+ singular `product` settings playing the same role | **`should`.** Collapse to one `product_list`. See [next section](#selector-heuristic--singular--list). |
116
+ | `products_list` instead of `product_list` | **`nit`.** Both valid; prefer `product_list`. |
117
+
118
+ ---
@@ -3,6 +3,7 @@ import { Command } from "commander";
3
3
  import {
4
4
  findMissingSectionReferences,
5
5
  validateSchemaText,
6
+ VALID_SETTING_TYPES,
6
7
  type BlocksSchemaType,
7
8
  type Diagnostic,
8
9
  type TemplateInput,
@@ -113,6 +114,18 @@ export function createLintCommand(): Command {
113
114
  }
114
115
  }
115
116
 
117
+ // Surface the canonical setting types once (not in every diagnostic) so a
118
+ // consumer fixing an "Invalid settings type" error has the valid set to
119
+ // hand without it bloating each message.
120
+ const hasInvalidSettingType = results.some(({ diagnostics }) =>
121
+ diagnostics.some(
122
+ (d) =>
123
+ d.target?.kind === "setting" &&
124
+ d.target.field === "type" &&
125
+ d.target.settingType !== undefined,
126
+ ),
127
+ );
128
+
116
129
  if (opts.json) {
117
130
  console.log(
118
131
  JSON.stringify({
@@ -120,6 +133,9 @@ export function createLintCommand(): Command {
120
133
  errors,
121
134
  warnings,
122
135
  filesChecked: liquidFiles.length,
136
+ ...(hasInvalidSettingType
137
+ ? { validSettingTypes: VALID_SETTING_TYPES }
138
+ : {}),
123
139
  files: results,
124
140
  }),
125
141
  );
@@ -148,8 +164,8 @@ function printText(
148
164
  d.severity === "error"
149
165
  ? chalk.red("error".padEnd(7))
150
166
  : chalk.yellow("warning".padEnd(7));
151
- // Only the first line — diagnostics like the invalid-setting-type list
152
- // carry a long multi-line body that the `--json` output preserves.
167
+ // Only the first line — a few messages (e.g. the `Invalid JSON:` parse
168
+ // error) carry a multi-line body that `--json` preserves in full.
153
169
  const message = d.message.split("\n")[0];
154
170
  console.log(` ${label} ${message}`);
155
171
  }