mountain-ui 1.0.22 → 1.0.24

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mountain-ui",
3
3
  "private": false,
4
- "version": "1.0.22",
4
+ "version": "1.0.24",
5
5
  "description": "A comprehensive UI component library for ERP systems with field types, entities, and registry management built with Svelte",
6
6
  "type": "module",
7
7
  "module": "index.js",
@@ -4,44 +4,83 @@
4
4
  import FieldInput from './FieldInput.svelte';
5
5
  import FormCtx from './FormCtx.svelte';
6
6
 
7
- let { ctx = {}, entityId, onSubmit = ()=>{}, type = 'create' } = $props();
7
+ let { ctx = {}, entityId, onSubmit = () => {}, type = 'create' } = $props();
8
8
 
9
9
  let detailsCtx = $state({});
10
10
 
11
11
  const entity = entityRegistry.select(entityId);
12
12
 
13
- function handleSubmit() {
14
- onSubmit({...ctx})
15
- }
13
+ function handleSubmit() {
14
+ onSubmit({ ...ctx });
15
+ }
16
+
17
+ let calculations = $state({});
18
+
19
+ function handleRegisterCalculation(config) {
20
+ calculations = {
21
+ ...calculations,
22
+ [config.id]: config
23
+ };
24
+ }
25
+
26
+ function handleChange(fieldId, value) {
27
+ ctx[fieldId] = value;
28
+
29
+ recalculate(fieldId);
30
+
31
+ ctx = { ...ctx };
32
+ }
33
+ function handleChangeDetails(fieldId, value) {
34
+ detailsCtx[fieldId] = value;
35
+
36
+ // si c est un type lien alors on parcour ses champs enfant et on reagis
37
+ const field = entityRegistry.getField(fieldId, entity.id)
38
+ if (field.type === "link") {
39
+ const entity = entityRegistry.get(field.props.linkId)
40
+ for (const linkedFields of entity.fields) {
41
+ recalculate(linkedFields.id)
42
+ }
43
+ }
44
+
45
+ detailsCtx = { ...detailsCtx };
46
+ }
47
+
48
+ function recalculate(changedFieldId) {
49
+ // on parcour les calcules et on verifie si un depend du champs changé
50
+ for (const calc of Object.values(calculations)) {
51
+ if (!calc.dependsOn.includes(changedFieldId)) continue;
52
+
53
+ calc.calculate(ctx);
54
+ }
55
+ }
16
56
  </script>
17
57
 
18
58
  {#if $entity}
19
- <div class="form">
20
- <FormCtx bind:ctx bind:detailsCtx>
21
- {#each $entity.fields as field}
22
- <FieldInput
23
- {detailsCtx}
24
- {ctx}
25
- onChangeDetails={(value) => {
26
- detailsCtx[field.id] = value;
27
- detailsCtx = { ...detailsCtx };
28
- }}
29
- onChange={(value) => {
30
- ctx[field.id] = value;
31
- ctx = { ...ctx };
32
- }}
33
- id={field.id}
34
- entityId={$entity.id}
35
- value={ctx?.[field.id] ?? null}
36
- ></FieldInput>
37
- {/each}
38
- <div class="button">
39
- <Button onClick={handleSubmit}>
40
- <h4>{type === 'create' ? 'créer' : 'éditer'}</h4>
41
- </Button>
42
- </div>
43
- </FormCtx>
44
- </div>
59
+ <div class="form">
60
+ <FormCtx bind:ctx bind:detailsCtx>
61
+ {#each $entity.fields as field}
62
+ <FieldInput
63
+ {detailsCtx}
64
+ {ctx}
65
+ onChangeDetails={(value) => {
66
+ handleChangeDetails(field.id, value);
67
+ }}
68
+ onChange={(value) => {
69
+ handleChange(field.id, value);
70
+ }}
71
+ id={field.id}
72
+ entityId={$entity.id}
73
+ value={ctx?.[field.id] ?? null}
74
+ registerCalculation={handleRegisterCalculation}
75
+ ></FieldInput>
76
+ {/each}
77
+ <div class="button">
78
+ <Button onClick={handleSubmit}>
79
+ <h4>{type === 'create' ? 'créer' : 'éditer'}</h4>
80
+ </Button>
81
+ </div>
82
+ </FormCtx>
83
+ </div>
45
84
  {/if}
46
85
 
47
86
  <style>
@@ -19,36 +19,34 @@
19
19
  ...props
20
20
  } = $props();
21
21
 
22
-
23
22
  let table = $state([createLine()]);
24
23
 
25
- onMount(()=>{
26
- if (value === null) return
24
+ onMount(() => {
25
+ if (value === null) return;
27
26
 
28
- const decodedValue = JSON.parse(value)
27
+ const decodedValue = JSON.parse(value);
29
28
 
30
- let newLines = []
29
+ let newLines = [];
31
30
 
32
- for (const line of decodedValue) {
33
- const lineId = line.id
34
- delete line.id
35
- const newLine = createLine(lineId, line)
36
- newLines.push(newLine)
37
- }
31
+ for (const line of decodedValue) {
32
+ const lineId = line.id;
33
+ delete line.id;
34
+ const newLine = createLine(lineId, line);
35
+ newLines.push(newLine);
36
+ }
38
37
 
39
- table = [...newLines]
40
- })
38
+ table = [...newLines];
39
+ });
41
40
 
42
41
  function createLine(dbId = null, line = null) {
43
42
  return {
44
43
  id: crypto.randomUUID(),
45
- dbId:dbId,
46
- ctx: line??{},
44
+ dbId: dbId,
45
+ ctx: line ?? {},
47
46
  detailsCtx: {}
48
47
  };
49
48
  }
50
49
 
51
-
52
50
  function handleAddLine() {
53
51
  table = [...table, createLine()];
54
52
  }
@@ -57,32 +55,74 @@
57
55
 
58
56
  function handleDeleteLine(lineIndex) {
59
57
  table = table.filter((_, i) => i !== lineIndex);
60
- handleChangeDetailsCtx();
58
+ onChangeDetails(table)
61
59
  handleChange();
62
60
  }
63
- function handleChangeDetailsCtx() {
64
- onChangeDetails(table);
61
+
62
+ let calculations = $state({});
63
+
64
+ function handleRegisterCalculation(config) {
65
+ calculations = {
66
+ ...calculations,
67
+ [config.id]: config
68
+ };
69
+ }
70
+
71
+ function handleChange(lineIndex, fieldId, value) {
72
+ table[lineIndex].ctx[fieldId] = value;
73
+
74
+ recalculate(lineIndex, fieldId);
75
+
76
+ table = [...table];
77
+
78
+ const newValue = JSON.stringify(
79
+ table.map((line) => {
80
+ const data = {
81
+ ...line.ctx
82
+ };
83
+
84
+ if (line.dbId != null) {
85
+ data.id = line.dbId;
86
+ }
87
+
88
+ return data;
89
+ })
90
+ );
91
+
92
+ onChange(newValue);
65
93
  }
66
- function handleChange() {
67
- const value = JSON.stringify(table.map((line) => {
68
- const data = {
69
- ...line.ctx,
70
- }
71
94
 
72
- if (line.dbId != null) {
73
- data.id = line.dbId
74
- }
95
+ function handleChangeDetails(lineIndex, fieldId, value) {
96
+ table[lineIndex].detailsCtx[fieldId] = value;
75
97
 
76
- return data
77
- } ));
78
-
98
+ // si c est un type lien alors on parcour ses champs enfant et on reagis
99
+ const field = entityRegistry.getField(fieldId, entity.id);
100
+ if (field.type === 'link') {
101
+ const entity = entityRegistry.get(field.props.linkId);
102
+ for (const linkedFields of entity.fields) {
103
+ recalculate(lineIndex, linkedFields.id);
104
+ }
105
+ }
79
106
 
80
- onChange(value);
107
+ table = [...table];
108
+
109
+
110
+ onChangeDetails(table);
111
+ }
112
+
113
+ function recalculate(lineIndex, changedFieldId) {
114
+ // on parcour les calcules et on verifie si un depend du champs changé
115
+ for (const calc of Object.values(calculations)) {
116
+ console.log(changedFieldId);
117
+ if (!calc.dependsOn.includes(changedFieldId)) continue;
118
+
119
+ calc.calculate(table[lineIndex].ctx);
120
+ }
81
121
  }
82
122
  </script>
83
123
 
84
124
  <div class="title">
85
- <Label {label} {required} {secret} {unique}></Label>
125
+ <Label {label} {required} {secret} {unique}></Label>
86
126
  </div>
87
127
  <ResponsiveTable.Root let:ctx>
88
128
  <ResponsiveTable.Header>
@@ -107,17 +147,14 @@
107
147
  detailsCtx={table[lineIndex].detailsCtx}
108
148
  ctx={table[lineIndex].ctx}
109
149
  onChangeDetails={(value) => {
110
- table[lineIndex].detailsCtx[row.fieldId] = value;
111
- table = [...table];
112
- handleChangeDetailsCtx();
150
+ handleChangeDetails(lineIndex, row.fieldId, value);
113
151
  }}
114
152
  onChange={(value) => {
115
- table[lineIndex].ctx[row.fieldId] = value;
116
- table = [...table];
117
- handleChange();
153
+ handleChange(lineIndex, row.fieldId, value);
118
154
  }}
119
155
  id={row.fieldId}
120
156
  value={table[lineIndex].ctx?.[row.fieldId] ?? null}
157
+ registerCalculation={handleRegisterCalculation}
121
158
  ></FieldInput>
122
159
  {/each}
123
160
  {#if columnIndex + 1 === columns.length}
@@ -167,17 +204,17 @@
167
204
  </ResponsiveTable.Body>
168
205
  </ResponsiveTable.Root>
169
206
  <div class="title">
170
- <Button onClick={handleAddLine}>
171
- <h5>ajouter une rangée</h5>
172
- </Button>
207
+ <Button onClick={handleAddLine}>
208
+ <h5>ajouter une rangée</h5>
209
+ </Button>
173
210
  </div>
174
211
 
175
212
  <style>
176
- .title {
177
- display: flex;
178
- align-items: center;
179
- width: 100%;
180
- }
213
+ .title {
214
+ display: flex;
215
+ align-items: center;
216
+ width: 100%;
217
+ }
181
218
  :global(.table-container .line):has(.delete :global(.button):hover) {
182
219
  background-color: var(--red-b);
183
220
  }
@@ -18,6 +18,7 @@
18
18
  detailsCtx = {},
19
19
  onChange = () => {},
20
20
  onChangeDetails = () => {},
21
+ registerCalculation = () => {},
21
22
  operator = '',
22
23
  column1 = '',
23
24
  column2 = '',
@@ -29,58 +30,95 @@
29
30
  const field1 = entityRegistry.selectField(column1);
30
31
  const field2 = entityRegistry.selectField(column2);
31
32
 
32
- $effect(() => {
33
- if (!$field1 || !$field2) return;
33
+ let previousValue1 = Symbol();
34
+ let previousValue2 = Symbol();
35
+
36
+ function getFieldValue(field, ctx) {
37
+ if (!field) return null;
38
+
39
+ // Champ local
40
+ if (field.entity_id === entity_id) {
41
+ let v = ctx[field.id];
34
42
 
35
- const raw1 = ctx[column1] ?? null;
36
- const raw2 = ctx[column2] ?? null;
43
+ if (v == null) return null;
37
44
 
38
- let value1 = raw1 ? parseFloat(raw1) : null;
39
- let value2 = raw2 ? parseFloat(raw2) : null;
45
+ v = parseFloat(v);
40
46
 
41
- if ($field1.type === 'number-float-percent') value1 /= 100;
42
- // si c est un lien on recupere le ctxDetails du produit
43
- if ($field1.entity_id != entity_id) {
44
- const linkField = entityRegistry.getLinkedField(entity_id, $field1.entity_id);
45
- value1 = parseFloat(detailsCtx[linkField.id]?.[$field1.normalized_name]?.flat) ?? 0.0;
47
+ if (field.type === 'number-float-percent') {
48
+ v /= 100;
49
+ }
50
+
51
+ return isNaN(v) ? 0 : v;
46
52
  }
47
53
 
48
- if ($field2.type === 'number-float-percent') value2 /= 100;
49
- // si c est un lien on recupere le ctxDetails du produit
50
- if ($field2.entity_id != entity_id) {
51
- const linkField = entityRegistry.getLinkedField(entity_id, $field2.entity_id);
52
- value2 = parseFloat(detailsCtx[linkField.id]?.[$field2.normalized_name]?.flat) ?? 0.0;
54
+ // Champ lié
55
+ const linkField = entityRegistry.getLinkedField(entity_id, field.entity_id);
56
+
57
+ if (!linkField) return null;
58
+
59
+ let v = detailsCtx[linkField.id]?.[field.normalized_name]?.flat;
60
+
61
+ if (v == null) return null;
62
+
63
+ v = parseFloat(v);
64
+
65
+ if (field.type === 'number-float-percent') {
66
+ v /= 100;
53
67
  }
54
68
 
55
- if (value1 == null || value2 == null) return;
69
+ return isNaN(v) ? 0 : v;
70
+ }
56
71
 
57
- if (isNaN(value1)) value1 = 0;
58
- if (isNaN(value2)) value2 = 0;
72
+ function calculate(ctx) {
73
+ if (!$field1 || !$field2) return;
59
74
 
60
- const oldValue = value;
75
+ const value1 = getFieldValue($field1, ctx);
76
+ const value2 = getFieldValue($field2, ctx);
77
+
78
+ if (value1 === null || value2 === null) return;
79
+
80
+ if (value1 === previousValue1 && value2 === previousValue2) {
81
+ return;
82
+ }
83
+
84
+ previousValue1 = value1;
85
+ previousValue2 = value2;
86
+
87
+ let result = null;
61
88
 
62
89
  switch (operator) {
63
90
  case '+':
64
- value = value1 + value2;
91
+ result = value1 + value2;
65
92
  break;
93
+
66
94
  case '-':
67
- value = value1 - value2;
95
+ result = value1 - value2;
68
96
  break;
97
+
69
98
  case '*':
70
- value = value1 * value2;
99
+ result = value1 * value2;
71
100
  break;
101
+
72
102
  case '/':
73
- value = value2 === 0 ? null : value1 / value2;
103
+ result = value2 === 0 ? null : value1 / value2;
74
104
  break;
75
105
  }
76
106
 
77
- if (oldValue !== value) {
78
- onChange(value);
107
+ if (result !== value) {
108
+ value = result;
109
+ onChange(result);
79
110
  }
80
- });
111
+ };
81
112
 
82
113
  onMount(() => {
83
114
  isMounted = true;
115
+
116
+ // On donne notre calcul au parent
117
+ registerCalculation({
118
+ id,
119
+ calculate,
120
+ dependsOn:[column1, column2]
121
+ });
84
122
  });
85
123
  </script>
86
124