@rettangoli/ui 0.1.2-rc2 → 0.1.2-rc20

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 (45) hide show
  1. package/dist/rettangoli-iife-layout.min.js +102 -32
  2. package/dist/rettangoli-iife-ui.min.js +182 -69
  3. package/package.json +5 -3
  4. package/src/cli/buildSvg.js +86 -0
  5. package/src/cli/index.js +1 -0
  6. package/src/components/breadcrumb/breadcrumb.handlers.js +9 -0
  7. package/src/components/breadcrumb/breadcrumb.store.js +29 -0
  8. package/src/components/breadcrumb/breadcrumb.view.yaml +64 -0
  9. package/src/components/dropdownMenu/dropdownMenu.handlers.js +4 -4
  10. package/src/components/dropdownMenu/dropdownMenu.store.js +5 -17
  11. package/src/components/dropdownMenu/dropdownMenu.view.yaml +15 -13
  12. package/src/components/form/form.handlers.js +133 -24
  13. package/src/components/form/form.store.js +123 -23
  14. package/src/components/form/form.view.yaml +137 -29
  15. package/src/components/pageOutline/pageOutline.handlers.js +1 -1
  16. package/src/components/popoverInput/popoverInput.handlers.js +99 -0
  17. package/src/components/popoverInput/popoverInput.store.js +48 -0
  18. package/src/components/popoverInput/popoverInput.view.yaml +55 -0
  19. package/src/components/select/select.handlers.js +2 -5
  20. package/src/components/select/select.view.yaml +3 -3
  21. package/src/components/sidebar/sidebar.view.yaml +1 -1
  22. package/src/components/sliderInput/sliderInput.handlers.js +24 -0
  23. package/src/components/sliderInput/sliderInput.store.js +17 -0
  24. package/src/components/sliderInput/sliderInput.view.yaml +42 -0
  25. package/src/components/table/table.handlers.js +1 -1
  26. package/src/components/tabs/tabs.handlers.js +10 -0
  27. package/src/components/tabs/tabs.store.js +29 -0
  28. package/src/components/tabs/tabs.view.yaml +64 -0
  29. package/src/components/waveform/waveform.handlers.js +92 -0
  30. package/src/components/waveform/waveform.store.js +17 -0
  31. package/src/components/waveform/waveform.view.yaml +38 -0
  32. package/src/entry-iife-layout.js +3 -0
  33. package/src/entry-iife-ui.js +4 -0
  34. package/src/index.js +5 -1
  35. package/src/primitives/dialog.js +208 -0
  36. package/src/primitives/input.js +32 -11
  37. package/src/primitives/popover.js +275 -0
  38. package/src/primitives/slider.js +8 -9
  39. package/src/styles/viewStyles.js +1 -0
  40. package/src/components/dialog/dialog.handlers.js +0 -5
  41. package/src/components/dialog/dialog.store.js +0 -25
  42. package/src/components/dialog/dialog.view.yaml +0 -44
  43. package/src/components/popover/popover.handlers.js +0 -5
  44. package/src/components/popover/popover.store.js +0 -12
  45. package/src/components/popover/popover.view.yaml +0 -57
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rettangoli/ui",
3
- "version": "0.1.2-rc2",
3
+ "version": "0.1.2-rc20",
4
4
  "description": "A UI component library for building web interfaces.",
5
5
  "main": "dist/rettangoli-esm.min.js",
6
6
  "type": "module",
@@ -9,7 +9,8 @@
9
9
  "src"
10
10
  ],
11
11
  "exports": {
12
- ".": "./src/index.js"
12
+ ".": "./src/index.js",
13
+ "./cli": "./src/cli/index.js"
13
14
  },
14
15
  "module": "./src/index.js",
15
16
  "repository": {
@@ -48,10 +49,11 @@
48
49
  "homepage": "https://github.com/yuusoft-org/rettangoli#readme",
49
50
  "dependencies": {
50
51
  "@floating-ui/dom": "^1.6.13",
52
+ "@rettangoli/fe": "0.0.7-rc11",
51
53
  "commander": "^13.1.0",
54
+ "jempl": "^0.1.2",
52
55
  "js-yaml": "^4.1.0",
53
56
  "liquidjs": "^10.21.0",
54
- "@rettangoli/fe": "0.0.7-rc4",
55
57
  "snabbdom": "^3.6.2"
56
58
  }
57
59
  }
@@ -0,0 +1,86 @@
1
+ import { readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs';
2
+ import { join, basename } from 'node:path';
3
+
4
+ function getAllSvgFiles(dir) {
5
+ const svgFiles = [];
6
+
7
+ function traverse(currentDir) {
8
+ const files = readdirSync(currentDir);
9
+
10
+ for (const file of files) {
11
+ const fullPath = join(currentDir, file);
12
+ const stats = statSync(fullPath);
13
+
14
+ if (stats.isDirectory()) {
15
+ traverse(fullPath);
16
+ } else if (file.endsWith('.svg')) {
17
+ svgFiles.push(fullPath);
18
+ }
19
+ }
20
+ }
21
+
22
+ traverse(dir);
23
+ return svgFiles;
24
+ }
25
+
26
+ function removeFrontmatter(content) {
27
+ // Look for a line containing only '---'
28
+ const lines = content.split('\n');
29
+
30
+ for (let i = 0; i < lines.length; i++) {
31
+ if (lines[i].trim() === '---') {
32
+ // Found the separator, return everything after it
33
+ return lines.slice(i + 1).join('\n').trim();
34
+ }
35
+ }
36
+
37
+ // No frontmatter separator found, return original content
38
+ return content;
39
+ }
40
+
41
+ const buildSvgIcons = (options) => {
42
+ const { dir, outfile } = options;
43
+
44
+ if (!dir || !outfile) {
45
+ console.error('Error: Both dir and outfile options are required');
46
+ return;
47
+ }
48
+
49
+ console.log(`Scanning for SVG files in: ${dir}`);
50
+
51
+ const svgFiles = getAllSvgFiles(dir);
52
+
53
+ if (svgFiles.length === 0) {
54
+ console.log('No SVG files found');
55
+ return;
56
+ }
57
+
58
+ console.log(`Found ${svgFiles.length} SVG files`);
59
+
60
+ const icons = {};
61
+
62
+ for (const filePath of svgFiles) {
63
+ const fileName = basename(filePath, '.svg');
64
+ let content = readFileSync(filePath, 'utf8');
65
+
66
+ content = removeFrontmatter(content);
67
+
68
+ content = content.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
69
+
70
+ icons[fileName] = content;
71
+ }
72
+
73
+ // Convert to custom format with single quotes for keys and backticks for values
74
+ const iconEntries = Object.entries(icons).map(([key, value]) => {
75
+ return ` '${key}': \`${value}\``;
76
+ });
77
+
78
+ const output = `window.rtglIcons = {\n${iconEntries.join(',\n')}\n};`;
79
+
80
+ writeFileSync(outfile, output);
81
+
82
+ console.log(`SVG icons written to: ${outfile}`);
83
+ console.log(`Total icons: ${Object.keys(icons).length}`);
84
+ };
85
+
86
+ export default buildSvgIcons;
@@ -0,0 +1 @@
1
+ export { default as buildSvg } from './buildSvg.js';
@@ -0,0 +1,9 @@
1
+ export const handleClickItem = (e, deps) => {
2
+ const { dispatchEvent } = deps;
3
+ const id = e.currentTarget.dataset.id;
4
+ dispatchEvent(new CustomEvent('item-click', {
5
+ detail: {
6
+ id
7
+ }
8
+ }));
9
+ }
@@ -0,0 +1,29 @@
1
+ export const INITIAL_STATE = Object.freeze({});
2
+
3
+ const blacklistedAttrs = ['id', 'class', 'style', 'slot'];
4
+
5
+ const stringifyAttrs = (attrs) => {
6
+ return Object.entries(attrs).filter(([key]) => !blacklistedAttrs.includes(key)).map(([key, value]) => `${key}=${value}`).join(' ');
7
+ }
8
+
9
+ export const toViewData = ({ props, attrs }) => {
10
+ const containerAttrString = stringifyAttrs(attrs);
11
+
12
+ const items = props.items || [];
13
+ const separator = props.separator || 'breadcrumb-arrow';
14
+
15
+ // Add separators between items, but not after the last one
16
+ const itemsWithSeparators = [];
17
+ items.forEach((item, index) => {
18
+ itemsWithSeparators.push(item);
19
+ if (index < items.length - 1) {
20
+ itemsWithSeparators.push({ isSeparator: true });
21
+ }
22
+ });
23
+
24
+ return {
25
+ containerAttrString,
26
+ items: itemsWithSeparators,
27
+ separator
28
+ };
29
+ }
@@ -0,0 +1,64 @@
1
+ elementName: rtgl-breadcrumb
2
+
3
+ viewDataSchema:
4
+ type: object
5
+ properties:
6
+ containerAttrString:
7
+ type: string
8
+ items:
9
+ type: array
10
+ items:
11
+ type: object
12
+ properties:
13
+ label:
14
+ type: string
15
+ id:
16
+ type: string
17
+ separator:
18
+ type: string
19
+
20
+ propsSchema:
21
+ type: object
22
+ properties:
23
+ items:
24
+ type: array
25
+ items:
26
+ type: object
27
+ properties:
28
+ label:
29
+ type: string
30
+ id:
31
+ type: string
32
+ separator:
33
+ type: string
34
+ default: "breadcrumb-arrow"
35
+
36
+ refs:
37
+ item-*:
38
+ eventListeners:
39
+ click:
40
+ handler: handleClickItem
41
+ events:
42
+ item-click:
43
+ type: object
44
+ properties:
45
+ item:
46
+ type: object
47
+ properties:
48
+ label:
49
+ type: string
50
+ id:
51
+ type: string
52
+ index:
53
+ type: number
54
+
55
+ template:
56
+ - rtgl-view d=h av=c g=md p=sm ${containerAttrString}:
57
+ - $for item in items:
58
+ - $if item.isSeparator:
59
+ - rtgl-svg wh=16 svg=${separator} c=mu-fg:
60
+ $elif item.id:
61
+ - rtgl-view#item-${item.id} data-id=${item.id} cur=p:
62
+ - rtgl-text s=sm c=mu-fg: "${item.label}"
63
+ $else:
64
+ - rtgl-text s=sm c=mu-fg: "${item.label}"
@@ -1,18 +1,18 @@
1
1
 
2
- export const handleClickPopoverOverlay = (e, deps) => {
2
+ export const handleClosePopover = (e, deps) => {
3
3
  const { dispatchEvent } = deps;
4
- dispatchEvent(new CustomEvent('click-overlay'));
4
+ dispatchEvent(new CustomEvent('close'));
5
5
  }
6
6
 
7
7
  export const handleClickMenuItem = (e, deps) => {
8
8
  const { dispatchEvent } = deps;
9
9
  const index = parseInt(e.currentTarget.id.replace('option-', ''));
10
10
  const item = deps.props.items[index];
11
-
11
+
12
12
  dispatchEvent(new CustomEvent('click-item', {
13
13
  detail: {
14
14
  index,
15
15
  item
16
16
  }
17
17
  }));
18
- }
18
+ }
@@ -2,24 +2,12 @@
2
2
  export const INITIAL_STATE = Object.freeze({
3
3
  });
4
4
 
5
- export const toViewData = ({ state, props }) => {
5
+ export const toViewData = ({ props, attrs }) => {
6
6
  return {
7
7
  items: props.items || [],
8
- isOpen: props.isOpen || false,
9
- position: props.position || {
10
- x: 0,
11
- y: 0,
12
- },
8
+ open: !!attrs.open,
9
+ x: attrs.x,
10
+ y: attrs.y,
11
+ placement: attrs.placement
13
12
  };
14
13
  }
15
-
16
- export const selectState = ({ state }) => {
17
- return state;
18
- }
19
-
20
- export const setState = (state) => {
21
- // do doSomething
22
- }
23
-
24
-
25
-
@@ -19,28 +19,31 @@ propsSchema:
19
19
  - label
20
20
  - item
21
21
  - separator
22
- isOpen:
23
- type: boolean
24
- position:
25
- type: object
26
- properties:
27
- x:
28
- type: number
29
- y:
30
- type: number
22
+
23
+ attrsSchema:
24
+ type: object
25
+ properties:
26
+ open:
27
+ type: string
28
+ x:
29
+ type: string
30
+ y:
31
+ type: string
32
+ placement:
33
+ type: string
31
34
 
32
35
  refs:
33
36
  popover:
34
37
  eventListeners:
35
- click-overlay:
36
- handler: handleClickPopoverOverlay
38
+ close:
39
+ handler: handleClosePopover
37
40
  option-*:
38
41
  eventListeners:
39
42
  click:
40
43
  handler: handleClickMenuItem
41
44
 
42
45
  template:
43
- - rtgl-popover#popover .isOpen=isOpen .position=position:
46
+ - rtgl-popover#popover ?open=${open} x=${x} y=${y} placement=${placement}:
44
47
  - rtgl-view wh=300 g=xs slot=content bgc=background br=md:
45
48
  - $for item, i in items:
46
49
  - $if item.type == 'label':
@@ -51,4 +54,3 @@ template:
51
54
  - rtgl-text: ${item.label}
52
55
  $elif item.type == 'separator':
53
56
  - rtgl-view w=f h=1 ph=lg mv=md bgc=bo:
54
-
@@ -1,13 +1,25 @@
1
- export const handleOnMount = (deps) => {
1
+ export const handleBeforeMount = (deps) => {
2
2
  const { store, props } = deps;
3
- store.setDefaultValues(props.defaultValues);
3
+ store.setFormValues(props.defaultValues);
4
4
  };
5
5
 
6
- const dispatchFormChange = (fieldName, fieldValue, formValues, dispatchEvent) => {
6
+ export const handleOnUpdate = (changes, deps) => {
7
+ const { oldAttrs, newAttrs } = changes;
8
+ const { store, props, render } = deps;
9
+
10
+ if (oldAttrs?.key === newAttrs?.key) {
11
+ return;
12
+ }
13
+
14
+ store.setFormValues(props.defaultValues);
15
+ render();
16
+ };
17
+
18
+ const dispatchFormChange = (name, fieldValue, formValues, dispatchEvent) => {
7
19
  dispatchEvent(
8
20
  new CustomEvent("form-change", {
9
21
  detail: {
10
- fieldName,
22
+ name,
11
23
  fieldValue,
12
24
  formValues,
13
25
  },
@@ -29,51 +41,148 @@ export const handleActionClick = (e, deps) => {
29
41
  };
30
42
 
31
43
  export const handleInputChange = (e, deps) => {
44
+ const { store, dispatchEvent, props } = deps;
45
+ const name = e.currentTarget.id.replace("input-", "");
46
+ // TODO fix double event
47
+ if (name && e.detail.value !== undefined) {
48
+ store.setFormFieldValue({
49
+ name: name,
50
+ value: e.detail.value,
51
+ props,
52
+ });
53
+ dispatchFormChange(
54
+ name,
55
+ e.detail.value,
56
+ store.selectFormValues(),
57
+ dispatchEvent,
58
+ );
59
+ }
60
+ };
61
+
62
+ export const handlePopoverInputChange = (e, deps) => {
32
63
  const { store, dispatchEvent } = deps;
33
- const id = e.currentTarget.id.replace("input-", "");
64
+ const name = e.currentTarget.id.replace("popover-input-", "");
34
65
  // TODO fix double event
35
- if (id && e.detail.value !== undefined) {
66
+ if (name && e.detail.value !== undefined) {
36
67
  store.setFormFieldValue({
37
- // TODO user field name instead of id
38
- fieldName: id,
68
+ name: name,
39
69
  value: e.detail.value,
70
+ props,
40
71
  });
41
- dispatchFormChange(id, e.detail.value, store.selectFormValues(), dispatchEvent);
72
+ dispatchFormChange(
73
+ name,
74
+ e.detail.value,
75
+ store.selectFormValues(),
76
+ dispatchEvent,
77
+ );
42
78
  }
43
79
  };
44
80
 
45
81
  export const handleSelectChange = (e, deps) => {
46
- const { store, dispatchEvent } = deps;
47
- const id = e.currentTarget.id.replace("select-", "");
48
- if (id && e.detail.selectedValue !== undefined) {
82
+ const { store, dispatchEvent, render, props } = deps;
83
+ const name = e.currentTarget.id.replace("select-", "");
84
+ if (name && e.detail.selectedValue !== undefined) {
49
85
  store.setFormFieldValue({
50
- fieldName: id,
86
+ name: name,
51
87
  value: e.detail.selectedValue,
88
+ props,
52
89
  });
53
- dispatchFormChange(id, e.detail.selectedValue, store.selectFormValues(), dispatchEvent);
90
+ dispatchFormChange(
91
+ name,
92
+ e.detail.selectedValue,
93
+ store.selectFormValues(),
94
+ dispatchEvent,
95
+ );
96
+ render();
54
97
  }
55
98
  };
56
99
 
57
100
  export const handleColorPickerChange = (e, deps) => {
58
- const { store, dispatchEvent } = deps;
59
- const id = e.currentTarget.id.replace("colorpicker-", "");
60
- if (id && e.detail.value !== undefined) {
101
+ const { store, dispatchEvent, props } = deps;
102
+ const name = e.currentTarget.id.replace("colorpicker-", "");
103
+ if (name && e.detail.value !== undefined) {
61
104
  store.setFormFieldValue({
62
- fieldName: id,
105
+ name: name,
63
106
  value: e.detail.value,
107
+ props,
64
108
  });
65
- dispatchFormChange(id, e.detail.value, store.selectFormValues(), dispatchEvent);
109
+ dispatchFormChange(
110
+ name,
111
+ e.detail.value,
112
+ store.selectFormValues(),
113
+ dispatchEvent,
114
+ );
66
115
  }
67
116
  };
68
117
 
69
118
  export const handleSliderChange = (e, deps) => {
70
- const { store, dispatchEvent } = deps;
71
- const id = e.currentTarget.id.replace("slider-", "");
72
- if (id && e.detail.value !== undefined) {
119
+ const { store, dispatchEvent, props } = deps;
120
+ const name = e.currentTarget.id.replace("slider-", "");
121
+ if (name && e.detail.value !== undefined) {
73
122
  store.setFormFieldValue({
74
- fieldName: id,
123
+ name: name,
75
124
  value: e.detail.value,
125
+ props,
76
126
  });
77
- dispatchFormChange(id, e.detail.value, store.selectFormValues(), dispatchEvent);
127
+ dispatchFormChange(
128
+ name,
129
+ e.detail.value,
130
+ store.selectFormValues(),
131
+ dispatchEvent,
132
+ );
78
133
  }
79
134
  };
135
+
136
+ export const handleSliderInputChange = (e, deps) => {
137
+ const { store, dispatchEvent, props } = deps;
138
+ const name = e.currentTarget.id.replace("slider-input-", "");
139
+ if (name && e.detail.value !== undefined) {
140
+ store.setFormFieldValue({
141
+ name: name,
142
+ value: e.detail.value,
143
+ props,
144
+ });
145
+ dispatchFormChange(
146
+ name,
147
+ e.detail.value,
148
+ store.selectFormValues(),
149
+ dispatchEvent,
150
+ );
151
+ }
152
+ };
153
+
154
+ export const handleImageClick = (e, deps) => {
155
+ if (e.type === "contextmenu") {
156
+ e.preventDefault();
157
+ }
158
+ const { dispatchEvent } = deps;
159
+ const name = e.currentTarget.id.replace("image-", "");
160
+ dispatchEvent(
161
+ new CustomEvent("extra-event", {
162
+ detail: {
163
+ name: name,
164
+ x: e.clientX,
165
+ y: e.clientY,
166
+ trigger: e.type,
167
+ },
168
+ }),
169
+ );
170
+ };
171
+
172
+ export const handleWaveformClick = (e, deps) => {
173
+ if (e.type === "contextmenu") {
174
+ e.preventDefault();
175
+ }
176
+ const { dispatchEvent } = deps;
177
+ const name = e.currentTarget.id.replace("waveform-", "");
178
+ dispatchEvent(
179
+ new CustomEvent("extra-event", {
180
+ detail: {
181
+ name: name,
182
+ x: e.clientX,
183
+ y: e.clientY,
184
+ trigger: e.type,
185
+ },
186
+ }),
187
+ );
188
+ };
@@ -1,45 +1,145 @@
1
+ import { parseAndRender } from "jempl";
2
+
3
+ function pick(obj, keys) {
4
+ return keys.reduce((acc, key) => {
5
+ if (key in obj) acc[key] = obj[key];
6
+ return acc;
7
+ }, {});
8
+ }
9
+
1
10
  export const INITIAL_STATE = Object.freeze({
2
- formValues: {}
11
+ formValues: {},
3
12
  });
4
13
 
5
- const blacklistedAttrs = ['id', 'class', 'style', 'slot'];
14
+ // Lodash-like utility functions for nested property access
15
+ const get = (obj, path, defaultValue = undefined) => {
16
+ const keys = path.split(/[\[\].]/).filter((key) => key !== "");
17
+ let current = obj;
18
+
19
+ for (const key of keys) {
20
+ if (current === null || current === undefined || !(key in current)) {
21
+ return defaultValue;
22
+ }
23
+ current = current[key];
24
+ }
25
+
26
+ return current;
27
+ };
28
+
29
+ const set = (obj, path, value) => {
30
+ const keys = path.split(/[\[\].]/).filter((key) => key !== "");
31
+
32
+ // If path contains array notation, delete the original flat key
33
+ if (path.includes("[") && path in obj) {
34
+ delete obj[path];
35
+ }
36
+
37
+ let current = obj;
38
+
39
+ for (let i = 0; i < keys.length - 1; i++) {
40
+ const key = keys[i];
41
+ if (
42
+ !(key in current) ||
43
+ typeof current[key] !== "object" ||
44
+ current[key] === null
45
+ ) {
46
+ // Check if next key is a number to create array
47
+ const nextKey = keys[i + 1];
48
+ const isArrayIndex = /^\d+$/.test(nextKey);
49
+ current[key] = isArrayIndex ? [] : {};
50
+ }
51
+ current = current[key];
52
+ }
53
+
54
+ current[keys[keys.length - 1]] = value;
55
+ return obj;
56
+ };
57
+
58
+ const blacklistedAttrs = ["id", "class", "style", "slot"];
6
59
 
7
60
  const stringifyAttrs = (attrs) => {
8
- return Object.entries(attrs).filter(([key]) => !blacklistedAttrs.includes(key)).map(([key, value]) => `${key}=${value}`).join(' ');
9
- }
61
+ return Object.entries(attrs)
62
+ .filter(([key]) => !blacklistedAttrs.includes(key))
63
+ .map(([key, value]) => `${key}=${value}`)
64
+ .join(" ");
65
+ };
66
+
67
+ export const selectForm = ({ state, props }) => {
68
+ const { form } = props;
69
+ const { context } = props;
70
+
71
+ if (context) {
72
+ return parseAndRender(form, context);
73
+ }
74
+
75
+ return form;
76
+ };
10
77
 
11
78
  export const toViewData = ({ state, props, attrs }) => {
12
79
  const containerAttrString = stringifyAttrs(attrs);
80
+ const defaultValues = props.defaultValues || {};
81
+
82
+ const form = selectForm({ state, props });
83
+ const fields = structuredClone(form.fields || []);
84
+ fields.forEach((field) => {
85
+ field.defaultValue = get(defaultValues, field.name);
86
+
87
+ if (field.inputType === "image") {
88
+ const src = field.src;
89
+ // Only set imageSrc if src exists and is not empty
90
+ field.imageSrc = src && src.trim() ? src : null;
91
+ // Set placeholder text
92
+ field.placeholderText = field.placeholder || "No Image";
93
+ }
94
+ if (field.inputType === "waveform") {
95
+ const waveformData = field.waveformData;
96
+ // Only set waveformData if it exists
97
+ field.waveformData = waveformData || null;
98
+ // Set placeholder text
99
+ field.placeholderText = field.placeholder || "No Waveform";
100
+ }
101
+ });
102
+
13
103
  return {
14
104
  containerAttrString,
15
- title: props.form?.title || '',
16
- description: props?.form?.description || '',
17
- fields: props?.form?.fields || [],
105
+ title: form?.title || "",
106
+ description: form?.description || "",
107
+ fields: fields,
18
108
  actions: props?.form?.actions || {
19
- buttons: []
109
+ buttons: [],
20
110
  },
21
- // TODO fix default values
22
111
  formValues: state.formValues,
23
112
  };
24
- }
113
+ };
25
114
 
26
115
  export const selectState = ({ state }) => {
27
116
  return state;
28
- }
117
+ };
29
118
 
30
- export const selectFormValues = ({ state }) => {
31
- return state.formValues;
32
- }
119
+ export const selectFormValues = ({ state, props }) => {
120
+ const form = selectForm({ state, props });
33
121
 
34
- export const setState = (state) => {
35
- // do doSomething
36
- }
122
+ return pick(
123
+ state.formValues,
124
+ form.fields.map((field) => field.name),
125
+ );
126
+ };
37
127
 
38
- export const setDefaultValues = (state, defaultValues) => {
39
- state.formValues = defaultValues || {};
40
- }
128
+ export const getFormFieldValue = ({ state }, name) => {
129
+ return get(state.formValues, name);
130
+ };
41
131
 
42
- export const setFormFieldValue = (state, { fieldName, value }) => {
43
- state.formValues[fieldName] = value;
44
- }
132
+ export const setFormValues = (state, defaultValues) => {
133
+ state.formValues = defaultValues || {};
134
+ };
45
135
 
136
+ export const setFormFieldValue = (state, { name, value, props }) => {
137
+ set(state.formValues, name, value);
138
+ // remove non visible values
139
+ const form = selectForm({ state, props });
140
+ const formValues = pick(
141
+ state.formValues,
142
+ form.fields.map((field) => field.name),
143
+ );
144
+ state.formValues = formValues;
145
+ };