@flowdrop/flowdrop 2.0.0-beta.3 → 2.0.0-beta.4

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 (49) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +5 -5
  3. package/dist/components/App.svelte +15 -146
  4. package/dist/components/Button.stories.svelte +65 -0
  5. package/dist/components/Button.stories.svelte.d.ts +19 -0
  6. package/dist/components/Button.svelte +62 -0
  7. package/dist/components/Button.svelte.d.ts +24 -0
  8. package/dist/components/ConfigForm.svelte +4 -4
  9. package/dist/components/EditorStatusBar.stories.svelte +44 -0
  10. package/dist/components/EditorStatusBar.stories.svelte.d.ts +27 -0
  11. package/dist/components/EditorStatusBar.svelte +99 -0
  12. package/dist/components/EditorStatusBar.svelte.d.ts +15 -0
  13. package/dist/components/IconButton.svelte +80 -0
  14. package/dist/components/IconButton.svelte.d.ts +30 -0
  15. package/dist/components/Input.svelte +74 -0
  16. package/dist/components/Input.svelte.d.ts +17 -0
  17. package/dist/components/Navbar.svelte +9 -4
  18. package/dist/components/Navbar.svelte.d.ts +3 -0
  19. package/dist/components/NodeSidebar.svelte +13 -111
  20. package/dist/components/NodeSwapPicker.svelte +10 -26
  21. package/dist/components/Select.svelte +53 -0
  22. package/dist/components/Select.svelte.d.ts +15 -0
  23. package/dist/components/Textarea.svelte +39 -0
  24. package/dist/components/Textarea.svelte.d.ts +12 -0
  25. package/dist/components/ThemeToggle.svelte +15 -89
  26. package/dist/components/form/FormArray.svelte +37 -157
  27. package/dist/components/form/FormCheckboxGroup.svelte +1 -1
  28. package/dist/components/form/FormField.svelte +5 -44
  29. package/dist/components/form/FormFieldLight.svelte +5 -44
  30. package/dist/components/form/FormFieldset.svelte +1 -1
  31. package/dist/components/form/FormNumberField.svelte +4 -32
  32. package/dist/components/form/FormRangeField.svelte +17 -7
  33. package/dist/components/form/FormSelect.svelte +13 -79
  34. package/dist/components/form/FormTextField.svelte +3 -39
  35. package/dist/components/form/FormTextarea.svelte +4 -43
  36. package/dist/components/form/resolveFieldType.d.ts +24 -0
  37. package/dist/components/form/resolveFieldType.js +55 -0
  38. package/dist/components/icons/CloseIcon.svelte +6 -0
  39. package/dist/components/icons/CloseIcon.svelte.d.ts +26 -0
  40. package/dist/components/playground/InputCollector.svelte +11 -46
  41. package/dist/messages/index.d.ts +1 -1
  42. package/dist/messages/index.js +1 -1
  43. package/dist/openapi/v1/openapi.yaml +2 -2
  44. package/dist/skins/drafter.js +41 -28
  45. package/dist/styles/base.css +247 -5
  46. package/dist/styles/tokens.css +6 -0
  47. package/dist/svelte-app.js +68 -107
  48. package/dist/utils/connections.js +14 -50
  49. package/package.json +1 -1
@@ -94,7 +94,7 @@
94
94
  aria-valuemax={max}
95
95
  aria-valuenow={numericValue}
96
96
  oninput={handleInput}
97
- style="--progress: {progressPercentage}%"
97
+ style="--progress: {progressPercentage}"
98
98
  />
99
99
  </div>
100
100
  <div class="form-range-values">
@@ -119,6 +119,16 @@
119
119
  }
120
120
 
121
121
  .form-range-field {
122
+ /* Thumb width; the fill edge is offset by half of this so it tracks the
123
+ thumb centre instead of the raw 0–100% of the track. */
124
+ --fd-range-thumb-size: 18px;
125
+ /* `--progress` is a unitless 0–100 set inline. The browser keeps the thumb
126
+ inside the track, so its centre travels from thumb/2 to (100% − thumb/2);
127
+ mirror that here so the colour fill lines up at every value, on load too. */
128
+ --fd-range-fill: calc(
129
+ var(--fd-range-thumb-size) / 2 + (100% - var(--fd-range-thumb-size)) * var(--progress, 0) /
130
+ 100
131
+ );
122
132
  width: 100%;
123
133
  height: 6px;
124
134
  border-radius: 3px;
@@ -127,8 +137,8 @@
127
137
  background: linear-gradient(
128
138
  to right,
129
139
  var(--fd-primary) 0%,
130
- var(--fd-primary) var(--progress, 0%),
131
- var(--fd-border) var(--progress, 0%),
140
+ var(--fd-primary) var(--fd-range-fill),
141
+ var(--fd-border) var(--fd-range-fill),
132
142
  var(--fd-border) 100%
133
143
  );
134
144
  cursor: pointer;
@@ -145,8 +155,8 @@
145
155
  .form-range-field::-webkit-slider-thumb {
146
156
  -webkit-appearance: none;
147
157
  appearance: none;
148
- width: 18px;
149
- height: 18px;
158
+ width: var(--fd-range-thumb-size);
159
+ height: var(--fd-range-thumb-size);
150
160
  border-radius: 50%;
151
161
  background: linear-gradient(135deg, var(--fd-background) 0%, var(--fd-muted) 100%);
152
162
  border: 2px solid var(--fd-primary);
@@ -180,8 +190,8 @@
180
190
 
181
191
  /* Firefox - Thumb */
182
192
  .form-range-field::-moz-range-thumb {
183
- width: 18px;
184
- height: 18px;
193
+ width: var(--fd-range-thumb-size);
194
+ height: var(--fd-range-thumb-size);
185
195
  border-radius: 50%;
186
196
  background: linear-gradient(135deg, var(--fd-background) 0%, var(--fd-muted) 100%);
187
197
  border: 2px solid var(--fd-primary);
@@ -9,7 +9,7 @@
9
9
  -->
10
10
 
11
11
  <script lang="ts">
12
- import Icon from '@iconify/svelte';
12
+ import Select from '../Select.svelte';
13
13
  import { normalizeOptions, type FieldOption } from './types.js';
14
14
 
15
15
  interface Props {
@@ -53,81 +53,15 @@
53
53
  }
54
54
  </script>
55
55
 
56
- <div class="form-select-wrapper">
57
- <select
58
- {id}
59
- class="form-select"
60
- value={value ?? ''}
61
- {disabled}
62
- aria-describedby={ariaDescribedBy}
63
- aria-required={required}
64
- onchange={handleChange}
65
- >
66
- {#each normalizedOptions as option (option.value)}
67
- <option value={option.value}>{option.label}</option>
68
- {/each}
69
- </select>
70
- <span class="form-select__icon" aria-hidden="true">
71
- <Icon icon="heroicons:chevron-down" />
72
- </span>
73
- </div>
74
-
75
- <style>
76
- .form-select-wrapper {
77
- position: relative;
78
- }
79
-
80
- .form-select {
81
- width: 100%;
82
- padding: 0.625rem 2.5rem 0.625rem 0.875rem;
83
- border: 1px solid var(--fd-border);
84
- border-radius: var(--fd-radius-lg);
85
- font-size: var(--fd-text-sm);
86
- font-family: inherit;
87
- color: var(--fd-foreground);
88
- background-color: var(--fd-background);
89
- transition: all var(--fd-transition-normal);
90
- box-shadow: var(--fd-shadow-sm);
91
- cursor: pointer;
92
- appearance: none;
93
- }
94
-
95
- .form-select:hover {
96
- border-color: var(--fd-border-strong);
97
- background-color: var(--fd-background);
98
- }
99
-
100
- .form-select:focus {
101
- border-color: var(--fd-ring);
102
- background-color: var(--fd-background);
103
- }
104
-
105
- .form-select:disabled {
106
- background-color: var(--fd-muted);
107
- border-color: var(--fd-border-muted);
108
- color: var(--fd-muted-foreground);
109
- cursor: not-allowed;
110
- opacity: 1;
111
- }
112
-
113
- .form-select__icon {
114
- position: absolute;
115
- right: 0.75rem;
116
- top: 50%;
117
- transform: translateY(-50%);
118
- pointer-events: none;
119
- color: var(--fd-muted-foreground);
120
- display: flex;
121
- align-items: center;
122
- transition: color var(--fd-transition-normal);
123
- }
124
-
125
- .form-select__icon :global(svg) {
126
- width: 1rem;
127
- height: 1rem;
128
- }
129
-
130
- .form-select:focus + .form-select__icon {
131
- color: var(--fd-primary);
132
- }
133
- </style>
56
+ <Select
57
+ {id}
58
+ value={value ?? ''}
59
+ {disabled}
60
+ aria-describedby={ariaDescribedBy}
61
+ aria-required={required}
62
+ onchange={handleChange}
63
+ >
64
+ {#each normalizedOptions as option (option.value)}
65
+ <option value={option.value}>{option.label}</option>
66
+ {/each}
67
+ </Select>
@@ -9,6 +9,8 @@
9
9
  -->
10
10
 
11
11
  <script lang="ts">
12
+ import Input from '../Input.svelte';
13
+
12
14
  interface Props {
13
15
  /** Field identifier */
14
16
  id: string;
@@ -45,10 +47,9 @@
45
47
  }
46
48
  </script>
47
49
 
48
- <input
50
+ <Input
49
51
  {id}
50
52
  type="text"
51
- class="form-text-field"
52
53
  value={value ?? ''}
53
54
  {placeholder}
54
55
  {disabled}
@@ -56,40 +57,3 @@
56
57
  aria-required={required}
57
58
  oninput={handleInput}
58
59
  />
59
-
60
- <style>
61
- .form-text-field {
62
- width: 100%;
63
- padding: 0.625rem 0.875rem;
64
- border: 1px solid var(--fd-border);
65
- border-radius: var(--fd-radius-lg);
66
- font-size: var(--fd-text-sm);
67
- font-family: inherit;
68
- color: var(--fd-foreground);
69
- background-color: var(--fd-background);
70
- transition: all var(--fd-transition-normal);
71
- box-shadow: var(--fd-shadow-sm);
72
- }
73
-
74
- .form-text-field::placeholder {
75
- color: var(--fd-muted-foreground);
76
- }
77
-
78
- .form-text-field:hover {
79
- border-color: var(--fd-border-strong);
80
- background-color: var(--fd-background);
81
- }
82
-
83
- .form-text-field:focus {
84
- border-color: var(--fd-ring);
85
- background-color: var(--fd-background);
86
- }
87
-
88
- .form-text-field:disabled {
89
- background-color: var(--fd-muted);
90
- border-color: var(--fd-border-muted);
91
- color: var(--fd-muted-foreground);
92
- cursor: not-allowed;
93
- opacity: 1;
94
- }
95
- </style>
@@ -9,6 +9,8 @@
9
9
  -->
10
10
 
11
11
  <script lang="ts">
12
+ import Textarea from '../Textarea.svelte';
13
+
12
14
  interface Props {
13
15
  /** Field identifier */
14
16
  id: string;
@@ -48,9 +50,8 @@
48
50
  }
49
51
  </script>
50
52
 
51
- <textarea
53
+ <Textarea
52
54
  {id}
53
- class="form-textarea"
54
55
  value={value ?? ''}
55
56
  {placeholder}
56
57
  {rows}
@@ -58,44 +59,4 @@
58
59
  aria-describedby={ariaDescribedBy}
59
60
  aria-required={required}
60
61
  oninput={handleInput}
61
- ></textarea>
62
-
63
- <style>
64
- .form-textarea {
65
- width: 100%;
66
- padding: 0.625rem 0.875rem;
67
- border: 1px solid var(--fd-border);
68
- border-radius: var(--fd-radius-lg);
69
- font-size: var(--fd-text-sm);
70
- font-family: inherit;
71
- color: var(--fd-foreground);
72
- background-color: var(--fd-background);
73
- transition: all var(--fd-transition-normal);
74
- box-shadow: var(--fd-shadow-sm);
75
- resize: vertical;
76
- min-height: 5rem;
77
- line-height: 1.5;
78
- }
79
-
80
- .form-textarea::placeholder {
81
- color: var(--fd-muted-foreground);
82
- }
83
-
84
- .form-textarea:hover {
85
- border-color: var(--fd-border-strong);
86
- background-color: var(--fd-background);
87
- }
88
-
89
- .form-textarea:focus {
90
- border-color: var(--fd-ring);
91
- background-color: var(--fd-background);
92
- }
93
-
94
- .form-textarea:disabled {
95
- background-color: var(--fd-muted);
96
- border-color: var(--fd-border-muted);
97
- color: var(--fd-muted-foreground);
98
- cursor: not-allowed;
99
- opacity: 1;
100
- }
101
- </style>
62
+ />
@@ -0,0 +1,24 @@
1
+ import type { FieldSchema } from './types.js';
2
+ /**
3
+ * The dependency-free field kinds that {@link FormField} and
4
+ * {@link FormFieldLight} render identically — i.e. everything that does not
5
+ * pull in a heavy editor or depend on the field registry.
6
+ */
7
+ export type BaseFieldType = 'checkbox-group' | 'select-enum' | 'select-options' | 'textarea' | 'range' | 'text' | 'number' | 'toggle' | 'array';
8
+ /**
9
+ * Resolve the basic field type for a schema — the single source of truth for
10
+ * the decision both the full and light field factories share.
11
+ *
12
+ * Returns `null` when none of the basic cases match, so each caller can apply
13
+ * its OWN special-case handling and fallback in its own order. The heavy and
14
+ * entry-point-specific cases (hidden, autocomplete, code/markdown/template
15
+ * editors, `object` → editor, registry-resolved components) are deliberately
16
+ * NOT decided here: `FormField` and `FormFieldLight` route those differently
17
+ * (static imports vs. the lazy field registry that keeps the `/form` light
18
+ * entry free of heavy deps), and must keep doing so before delegating here.
19
+ *
20
+ * Order matters and mirrors the original in-component chains: `enum` and
21
+ * `oneOf` are checked before the primitive `type` branches because option
22
+ * schemas frequently carry `type: 'string'`.
23
+ */
24
+ export declare function resolveBaseFieldType(schema: FieldSchema): BaseFieldType | null;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Resolve the basic field type for a schema — the single source of truth for
3
+ * the decision both the full and light field factories share.
4
+ *
5
+ * Returns `null` when none of the basic cases match, so each caller can apply
6
+ * its OWN special-case handling and fallback in its own order. The heavy and
7
+ * entry-point-specific cases (hidden, autocomplete, code/markdown/template
8
+ * editors, `object` → editor, registry-resolved components) are deliberately
9
+ * NOT decided here: `FormField` and `FormFieldLight` route those differently
10
+ * (static imports vs. the lazy field registry that keeps the `/form` light
11
+ * entry free of heavy deps), and must keep doing so before delegating here.
12
+ *
13
+ * Order matters and mirrors the original in-component chains: `enum` and
14
+ * `oneOf` are checked before the primitive `type` branches because option
15
+ * schemas frequently carry `type: 'string'`.
16
+ */
17
+ export function resolveBaseFieldType(schema) {
18
+ // Enum with multiple selection -> checkbox group
19
+ if (schema.enum && schema.multiple) {
20
+ return 'checkbox-group';
21
+ }
22
+ // Enum with single selection -> select
23
+ if (schema.enum) {
24
+ return 'select-enum';
25
+ }
26
+ // oneOf with labeled options (standard JSON Schema) -> select
27
+ if (schema.oneOf && schema.oneOf.length > 0) {
28
+ return 'select-options';
29
+ }
30
+ // Multiline string -> textarea
31
+ if (schema.type === 'string' && schema.format === 'multiline') {
32
+ return 'textarea';
33
+ }
34
+ // Range slider for number/integer with format: "range"
35
+ if ((schema.type === 'number' || schema.type === 'integer') && schema.format === 'range') {
36
+ return 'range';
37
+ }
38
+ // String -> text field
39
+ if (schema.type === 'string') {
40
+ return 'text';
41
+ }
42
+ // Number or integer -> number field
43
+ if (schema.type === 'number' || schema.type === 'integer') {
44
+ return 'number';
45
+ }
46
+ // Boolean -> toggle
47
+ if (schema.type === 'boolean') {
48
+ return 'toggle';
49
+ }
50
+ // Array -> array field
51
+ if (schema.type === 'array') {
52
+ return 'array';
53
+ }
54
+ return null;
55
+ }
@@ -0,0 +1,6 @@
1
+ <!-- Inline SVG equivalent of mdi:close (Material Design Icons) -->
2
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
3
+ <path
4
+ d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"
5
+ />
6
+ </svg>
@@ -0,0 +1,26 @@
1
+ export default CloseIcon;
2
+ type CloseIcon = SvelteComponent<{
3
+ [x: string]: never;
4
+ }, {
5
+ [evt: string]: CustomEvent<any>;
6
+ }, {}> & {
7
+ $$bindings?: string | undefined;
8
+ };
9
+ declare const CloseIcon: $$__sveltets_2_IsomorphicComponent<{
10
+ [x: string]: never;
11
+ }, {
12
+ [evt: string]: CustomEvent<any>;
13
+ }, {}, {}, string>;
14
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
15
+ new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
16
+ $$bindings?: Bindings;
17
+ } & Exports;
18
+ (internal: unknown, props: {
19
+ $$events?: Events;
20
+ $$slots?: Slots;
21
+ }): Exports & {
22
+ $set?: any;
23
+ $on?: any;
24
+ };
25
+ z_$$bindings?: Bindings;
26
+ }
@@ -8,6 +8,9 @@
8
8
 
9
9
  <script lang="ts">
10
10
  import Icon from '@iconify/svelte';
11
+ import Input from '../Input.svelte';
12
+ import Select from '../Select.svelte';
13
+ import Textarea from '../Textarea.svelte';
11
14
  import { slide } from 'svelte/transition';
12
15
  import type { PlaygroundInputField } from '../../types/playground.js';
13
16
  import { getInstance } from '../../stores/getInstance.svelte.js';
@@ -171,9 +174,8 @@
171
174
 
172
175
  {#if hasEnumOptions(field)}
173
176
  <!-- Select for enum fields -->
174
- <select
177
+ <Select
175
178
  id="input-{field.nodeId}-{field.fieldId}"
176
- class="input-collector__select"
177
179
  value={getValue(field)}
178
180
  onchange={(e) => updateValue(field, e.currentTarget.value)}
179
181
  >
@@ -181,17 +183,16 @@
181
183
  {#each field.schema?.enum ?? [] as option (option)}
182
184
  <option value={String(option)}>{option}</option>
183
185
  {/each}
184
- </select>
186
+ </Select>
185
187
  {:else if getInputType(field) === 'textarea'}
186
188
  <!-- Textarea for multiline -->
187
- <textarea
189
+ <Textarea
188
190
  id="input-{field.nodeId}-{field.fieldId}"
189
- class="input-collector__textarea"
190
191
  placeholder={field.schema?.description ?? `Enter ${field.label}`}
191
192
  value={String(getValue(field) ?? '')}
192
193
  oninput={(e) => updateValue(field, e.currentTarget.value)}
193
- rows="3"
194
- ></textarea>
194
+ rows={3}
195
+ />
195
196
  {:else if getInputType(field) === 'checkbox'}
196
197
  <!-- Checkbox for boolean -->
197
198
  <label class="input-collector__checkbox-wrapper">
@@ -208,10 +209,10 @@
208
209
  </label>
209
210
  {:else if getInputType(field) === 'number'}
210
211
  <!-- Number input -->
211
- <input
212
+ <Input
212
213
  id="input-{field.nodeId}-{field.fieldId}"
213
214
  type="number"
214
- class="input-collector__input"
215
+ class="flowdrop-input--numeric"
215
216
  placeholder={field.schema?.description ?? `Enter ${field.label}`}
216
217
  value={Number(getValue(field) ?? 0)}
217
218
  min={field.schema?.minimum}
@@ -220,10 +221,9 @@
220
221
  />
221
222
  {:else}
222
223
  <!-- Text input (default) -->
223
- <input
224
+ <Input
224
225
  id="input-{field.nodeId}-{field.fieldId}"
225
226
  type="text"
226
- class="input-collector__input"
227
227
  placeholder={field.schema?.description ?? `Enter ${field.label}`}
228
228
  value={String(getValue(field) ?? '')}
229
229
  oninput={(e) => updateValue(field, e.currentTarget.value)}
@@ -351,41 +351,6 @@
351
351
  color: var(--fd-error);
352
352
  }
353
353
 
354
- .input-collector__input,
355
- .input-collector__select,
356
- .input-collector__textarea {
357
- padding: var(--fd-space-xs) var(--fd-space-md);
358
- border: 1px solid var(--fd-border);
359
- border-radius: var(--fd-radius-lg);
360
- font-size: var(--fd-text-sm);
361
- font-family: inherit;
362
- color: var(--fd-foreground);
363
- background-color: var(--fd-background);
364
- transition:
365
- border-color var(--fd-transition-normal),
366
- box-shadow var(--fd-transition-normal);
367
- }
368
-
369
- .input-collector__input:focus,
370
- .input-collector__select:focus,
371
- .input-collector__textarea:focus {
372
- border-color: var(--fd-primary);
373
- }
374
-
375
- .input-collector__input::placeholder,
376
- .input-collector__textarea::placeholder {
377
- color: var(--fd-muted-foreground);
378
- }
379
-
380
- .input-collector__textarea {
381
- resize: vertical;
382
- min-height: 80px;
383
- }
384
-
385
- .input-collector__select {
386
- cursor: pointer;
387
- }
388
-
389
354
  .input-collector__checkbox-wrapper {
390
355
  display: flex;
391
356
  align-items: center;
@@ -2,7 +2,7 @@
2
2
  * Messages module — typed, overridable, translation-ready user-facing strings.
3
3
  *
4
4
  * See `./defaults.ts` for the canonical shape, `./context.ts` for the runtime
5
- * plumbing, and the i18n guide in `apps/docs` for consumer recipes.
5
+ * plumbing, and the i18n guide in the docs site (`.docs/`) for consumer recipes.
6
6
  */
7
7
  export { defaultMessages } from './defaults.js';
8
8
  export { mergeMessages } from './merge.js';
@@ -2,7 +2,7 @@
2
2
  * Messages module — typed, overridable, translation-ready user-facing strings.
3
3
  *
4
4
  * See `./defaults.ts` for the canonical shape, `./context.ts` for the runtime
5
- * plumbing, and the i18n guide in `apps/docs` for consumer recipes.
5
+ * plumbing, and the i18n guide in the docs site (`.docs/`) for consumer recipes.
6
6
  */
7
7
  export { defaultMessages } from './defaults.js';
8
8
  export { mergeMessages } from './merge.js';
@@ -37,8 +37,8 @@ info:
37
37
  email: shibinkidd@gmail.com
38
38
  url: https://www.drupal.org/project/issues/flowdrop?categories=All
39
39
  servers:
40
- - url: http://localhost:5173/api/flowdrop
41
- description: Local development server (Svelte)
40
+ - url: http://localhost:7104/api/flowdrop
41
+ description: Local development server
42
42
  - url: https://flowdrop.ddev.site/api/flowdrop
43
43
  description: Local Drupal server
44
44
  security: