@fw-components/formula-editor 2.3.4-linting.0 → 2.3.4-notion-update.0

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.
@@ -5,39 +5,28 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { html, LitElement } from "lit";
8
- import { customElement, property, query, state } from "lit/decorators.js";
9
- import { getFormulaTokens } from "./utils/get-formula-tokens.js";
8
+ import { customElement, property, state, query } from "lit/decorators.js";
9
+ import "./suggestion-menu.js";
10
10
  import { Parser } from "./utils/parser.js";
11
11
  import { FormulaEditorStyles } from "./styles/editor.js";
12
+ import { getFormulaTokens } from "./utils/get-formula-tokens.js";
12
13
  let FormulaEditor = class FormulaEditor extends LitElement {
13
- /**
14
- * Formula Parser
15
- */
16
- _parser;
17
- recommendations = [];
18
- currentCursorPosition = 0;
19
- /**
20
- * user input event type
21
- */
22
- lastInputType = "";
23
- _selectedRecommendation = "";
24
- isFocused = false;
25
- /**
26
- * Text area input value
27
- */
28
- formulaString = "";
29
- placeholder = "Type your formula...";
30
- recommendationLabels = new Map();
31
- label = "";
32
- variables = new Map();
33
- variableType = "";
34
- minSuggestionLen = 2;
35
- errorString = "";
36
- formulaRegex = /.*/;
37
- allowedNumbers = true;
38
- allowedOperators = new Set();
39
- editor;
40
- suggestionMenu;
14
+ constructor() {
15
+ super(...arguments);
16
+ this.recommendations = [];
17
+ this.currentCursorPosition = 0;
18
+ this.isFocused = false;
19
+ /**
20
+ * Text area input value
21
+ */
22
+ this.formulaString = "";
23
+ this.placeholder = "Type your formula...";
24
+ this.recommendationLabels = new Map();
25
+ this.variables = new Map();
26
+ this.minSuggestionLen = 2;
27
+ this.errorString = "";
28
+ this.allowedNumbers = true;
29
+ }
41
30
  updated(_changedProperties) {
42
31
  if (_changedProperties.has("formulaString")) {
43
32
  if (!this.formulaString?.trim()) {
@@ -77,7 +66,7 @@ let FormulaEditor = class FormulaEditor extends LitElement {
77
66
  this.currentCursorPosition = this.editor.selectionStart;
78
67
  const { recommendations, errorString, formattedString, newCursorPosition } = this._parser.parseInput(this.formulaString, this.currentCursorPosition, recommendation);
79
68
  this.recommendations = recommendations;
80
- this.errorString = errorString || "";
69
+ this.errorString = errorString;
81
70
  /**
82
71
  * Don't modify the text stream manually if the text is being composed,
83
72
  * unless the user manually chooses to do so by selecting a recommendation.
@@ -103,7 +92,7 @@ let FormulaEditor = class FormulaEditor extends LitElement {
103
92
  recommendations: this.recommendations,
104
93
  formulaTokens: getFormulaTokens(this.formulaString || "", this.formulaRegex)
105
94
  },
106
- bubbles: true
95
+ bubbles: true,
107
96
  }));
108
97
  }
109
98
  formatFormula() {
@@ -142,9 +131,7 @@ let FormulaEditor = class FormulaEditor extends LitElement {
142
131
  }
143
132
  render() {
144
133
  return html `
145
- <style>
146
- ${FormulaEditorStyles}
147
- </style>
134
+ <style>${FormulaEditorStyles}</style>
148
135
 
149
136
  ${this.label ? html `<label for="fw-formula-editor" class="editor-label">${this.label}</label>` : ""}
150
137
 
@@ -168,7 +155,7 @@ let FormulaEditor = class FormulaEditor extends LitElement {
168
155
  .onRecommendationClick=${this.onRecommendationClick.bind(this)}
169
156
  .recommendationLabels=${this.recommendationLabels}
170
157
  ></suggestion-menu>`
171
- : ""}
158
+ : ''}
172
159
  `;
173
160
  }
174
161
  };
@@ -194,31 +181,31 @@ __decorate([
194
181
  property()
195
182
  ], FormulaEditor.prototype, "placeholder", void 0);
196
183
  __decorate([
197
- property({ type: Object })
184
+ property()
198
185
  ], FormulaEditor.prototype, "recommendationLabels", void 0);
199
186
  __decorate([
200
- property({ type: String })
187
+ property()
201
188
  ], FormulaEditor.prototype, "label", void 0);
202
189
  __decorate([
203
- property({ type: Object })
190
+ property()
204
191
  ], FormulaEditor.prototype, "variables", void 0);
205
192
  __decorate([
206
- property({ type: String })
193
+ property()
207
194
  ], FormulaEditor.prototype, "variableType", void 0);
208
195
  __decorate([
209
- property({ type: Number })
196
+ property()
210
197
  ], FormulaEditor.prototype, "minSuggestionLen", void 0);
211
198
  __decorate([
212
- property({ type: String })
199
+ property()
213
200
  ], FormulaEditor.prototype, "errorString", void 0);
214
201
  __decorate([
215
- property({ type: Object })
202
+ property()
216
203
  ], FormulaEditor.prototype, "formulaRegex", void 0);
217
204
  __decorate([
218
- property({ type: Boolean })
205
+ property()
219
206
  ], FormulaEditor.prototype, "allowedNumbers", void 0);
220
207
  __decorate([
221
- property({ type: Object })
208
+ property()
222
209
  ], FormulaEditor.prototype, "allowedOperators", void 0);
223
210
  __decorate([
224
211
  query("#fw-formula-editor")
@@ -8,11 +8,13 @@ import { html, LitElement } from "lit";
8
8
  import { customElement, property, query, state } from "lit/decorators.js";
9
9
  import { SuggestionMenuStyles } from "./styles/suggestion-menu";
10
10
  let SuggestionMenu = class SuggestionMenu extends LitElement {
11
- recommendations = [];
12
- recommendationLabels = new Map();
13
- onRecommendationClick = () => { };
14
- _currentFocusedIndex = -1;
15
- suggestionList;
11
+ constructor() {
12
+ super(...arguments);
13
+ this.recommendations = [];
14
+ this.recommendationLabels = new Map();
15
+ this.onRecommendationClick = () => { };
16
+ this._currentFocusedIndex = -1;
17
+ }
16
18
  scrollToSelectedRecommendation(index) {
17
19
  const listItem = this.suggestionList?.querySelectorAll("li")[index];
18
20
  if (!listItem)
@@ -43,13 +45,12 @@ let SuggestionMenu = class SuggestionMenu extends LitElement {
43
45
  }
44
46
  render() {
45
47
  return html `
46
- <style>
47
- ${SuggestionMenuStyles}
48
- </style>
48
+ <style>${SuggestionMenuStyles}</style>
49
49
  <ul class="fw-formula-suggestion-menu" @mousedown=${(e) => e.preventDefault()}>
50
- ${this.recommendations.map((recommendation, index) => html `<li class="${this._currentFocusedIndex === index ? "selected" : ""}" @click=${(e) => this.handleRecommendationSelect(index)}>
51
- ${this.recommendationLabels.get(recommendation) ?? recommendation}
52
- </li>`)}
50
+ ${this.recommendations.map((recommendation, index) => html `<li
51
+ class="${this._currentFocusedIndex === index ? "selected" : ""}"
52
+ @click=${(e) => this.handleRecommendationSelect(index)}
53
+ >${this.recommendationLabels.get(recommendation) ?? recommendation}</li>`)}
53
54
  </ul>
54
55
  `;
55
56
  }
@@ -6,12 +6,9 @@ export var Expectation;
6
6
  })(Expectation || (Expectation = {}));
7
7
  export class Formula {
8
8
  constructor(name, formulaString, precision = -1) {
9
+ this.error = null;
9
10
  this.name = name || "";
10
11
  this.formulaString = formulaString || "";
11
12
  this.precision = precision;
12
13
  }
13
- name;
14
- formulaString;
15
- precision;
16
- error = null;
17
14
  }
@@ -1,17 +1,11 @@
1
- import { mathematicalOperators, operatorPrecedence, unaryOperators } from "./constants.js";
2
- import { getFormulaTokens } from "./get-formula-tokens.js";
3
- import { Queue } from "./queue.js";
1
+ import Big from "big.js";
4
2
  import { Recommender } from "./recommendor.js";
5
3
  import { Stack } from "./stack.js";
6
- import Big from "big.js";
4
+ import { Queue } from "./queue.js";
7
5
  import { Expectation } from "../types";
6
+ import { operatorPrecedence, unaryOperators, mathematicalOperators } from "./constants.js";
7
+ import { getFormulaTokens } from "./get-formula-tokens.js";
8
8
  export class Parser {
9
- _recommender;
10
- variables;
11
- formulaRegex;
12
- allowedNumbers;
13
- allowedOperators;
14
- variableType;
15
9
  constructor(variables, minSuggestionLen, formulaRegex = /[A-Za-z0-9_#@.]+|[-+(),*^/\s]/g, allowedNumbers = true, allowedOperators = mathematicalOperators, variableType = "") {
16
10
  this.variables = variables;
17
11
  this.formulaRegex = formulaRegex;
@@ -26,7 +20,7 @@ export class Parser {
26
20
  return !Number.isNaN(Number(value));
27
21
  }
28
22
  formatFormulaToken(token) {
29
- for (const existingKey of this.variables.keys()) {
23
+ for (let existingKey of this.variables.keys()) {
30
24
  if (existingKey.toLowerCase() === token.toLowerCase()) {
31
25
  return existingKey;
32
26
  }
@@ -44,7 +38,7 @@ export class Parser {
44
38
  recommendations: [],
45
39
  formattedString: "",
46
40
  newCursorPosition: prevCurPos ?? -1,
47
- errorString: null
41
+ errorString: null,
48
42
  };
49
43
  if (!formula.trim() && recommendation) {
50
44
  parseOutput.formattedString = recommendation;
@@ -79,6 +73,7 @@ export class Parser {
79
73
  recommendation = null;
80
74
  return;
81
75
  }
76
+ ;
82
77
  const updatedTokenLength = recommendation.length - token.length;
83
78
  parseOutput.newCursorPosition = Math.min(parseOutput.newCursorPosition, formula.length) + updatedTokenLength;
84
79
  token = recommendation;
@@ -89,7 +84,7 @@ export class Parser {
89
84
  /**
90
85
  * Error checks
91
86
  * skip error check if there is one already
92
- */
87
+ */
93
88
  if (expectation != Expectation.UNDEFINED) {
94
89
  /**
95
90
  * Unknown symbol/variable/word
@@ -106,37 +101,33 @@ export class Parser {
106
101
  parseOutput.errorString = "Unexpected closing bracket. Make sure all opening brackets '(' have matching closing brackets ')'.";
107
102
  expectation = Expectation.UNDEFINED;
108
103
  }
109
- else if (
110
104
  /**
111
105
  * Operator or ')' after an operator (Eg: '23 / *' or '23 / )')
112
106
  * No error for Unary `+` and `-` as they might represent a positive or negative number respectively
113
107
  */
114
- expectation === Expectation.VARIABLE &&
115
- !isNumber &&
116
- !isSpace &&
117
- token != "(" &&
118
- !(unaryOperators.includes(token) && (!parsedString.trim() || previousToken === "(" || this.allowedOperators.has(previousToken)))) {
119
- parseOutput.errorString = `Please use ${this.variableType} ${this.variableType && this.allowedNumbers ? " or " : ""} ${this.allowedNumbers ? "numbers" : ""} after '${previousToken}'.`;
108
+ else if (expectation === Expectation.VARIABLE && !isNumber && !isSpace && token != "("
109
+ && !((unaryOperators.includes(token)) && (!parsedString.trim() || previousToken === "(" || this.allowedOperators.has(previousToken)))) {
110
+ parseOutput.errorString = `Please use ${this.variableType} ${this.variableType && this.allowedNumbers ? " or " : ''} ${this.allowedNumbers ? "numbers" : ""} after '${previousToken}'.`;
120
111
  expectation = Expectation.UNDEFINED;
121
112
  }
113
+ /**
114
+ * Multiple number/variable together without operator
115
+ */
122
116
  else if (expectation === Expectation.OPERATOR && !isOperator && !isSpace && token != ")") {
123
- /**
124
- * Multiple number/variable together without operator
125
- */
126
117
  parseOutput.errorString = `Please use mathematical operators (${Array.from(this.allowedOperators).join(" ")}) after '${previousToken}'.`;
127
118
  expectation = Expectation.UNDEFINED;
128
119
  }
120
+ /**
121
+ * division by zero
122
+ */
129
123
  else if (isNumber && previousToken === "/" && (this.variables.get(token) === 0 || Number(token) === 0)) {
130
- /**
131
- * division by zero
132
- */
133
124
  parseOutput.errorString = `Division by zero is not possible.`;
134
125
  expectation = Expectation.UNDEFINED;
135
126
  }
127
+ /**
128
+ * Empty brackets
129
+ */
136
130
  else if (previousToken === "(" && token === ")") {
137
- /**
138
- * Empty brackets
139
- */
140
131
  parseOutput.errorString = `Please don't use empty brackets ().`;
141
132
  expectation = Expectation.UNDEFINED;
142
133
  }
@@ -187,7 +178,7 @@ export class Parser {
187
178
  let currentTokens = "";
188
179
  // Check if variables include unary operators `-` and `+`.
189
180
  for (const token of tokens) {
190
- if (unaryOperators.includes(token) && (!currentTokens.trim() || previousToken === "(" || this.allowedOperators.has(previousToken))) {
181
+ if ((unaryOperators.includes(token)) && (!currentTokens.trim() || previousToken === "(" || this.allowedOperators.has(previousToken))) {
191
182
  carriedToken = token;
192
183
  }
193
184
  else if (carriedToken) {
@@ -244,7 +235,7 @@ export class Parser {
244
235
  let parsedLeftExpression;
245
236
  let parsedRightExpression;
246
237
  // check if the symbol is a number or variable or unaryOperatorPreceded Variable
247
- if ((unaryOperators.includes(symbol[0]) && this.variables.has(symbol.substring(1))) ||
238
+ if (((unaryOperators.includes(symbol[0])) && this.variables.has(symbol.substring(1))) ||
248
239
  this.variables.has(symbol) ||
249
240
  (!Number.isNaN(parseFloat(symbol)) && Number.isFinite(parseFloat(symbol)))) {
250
241
  resultStack.push(symbol);
@@ -252,14 +243,21 @@ export class Parser {
252
243
  }
253
244
  // If symbol is an operator, check operatorStack, adds brackets accordingly to the result and add it to operatorStack
254
245
  else if (Object.keys(operatorPrecedence).includes(symbol)) {
255
- const [rightExpression, leftExpression, operatorA, operatorB] = [resultStack.pop(), resultStack.pop(), operatorStack.pop(), operatorStack.pop()];
256
- if (operatorPrecedence[operatorB] <= operatorPrecedence[symbol] || (operatorPrecedence[operatorB] === operatorPrecedence[symbol] && ["/", "-"].includes(symbol))) {
246
+ const [rightExpression, leftExpression, operatorA, operatorB] = [
247
+ resultStack.pop(),
248
+ resultStack.pop(),
249
+ operatorStack.pop(),
250
+ operatorStack.pop(),
251
+ ];
252
+ if ((operatorPrecedence[operatorB] <= operatorPrecedence[symbol]) ||
253
+ (operatorPrecedence[operatorB] === operatorPrecedence[symbol] && ["/", "-"].includes(symbol))) {
257
254
  parsedLeftExpression = `(${leftExpression})`;
258
255
  }
259
256
  else {
260
257
  parsedLeftExpression = leftExpression;
261
258
  }
262
- if (operatorPrecedence[operatorA] <= operatorPrecedence[symbol] || (operatorPrecedence[operatorA] === operatorPrecedence[symbol] && ["/", "-"].includes(symbol))) {
259
+ if (operatorPrecedence[operatorA] <= operatorPrecedence[symbol] ||
260
+ (operatorPrecedence[operatorA] === operatorPrecedence[symbol] && ["/", "-"].includes(symbol))) {
263
261
  parsedRightExpression = `(${rightExpression})`;
264
262
  }
265
263
  else {
@@ -279,7 +277,7 @@ export class Parser {
279
277
  const formulaRPN = this.buildRPN(formula);
280
278
  const calculationResult = {
281
279
  result: undefined,
282
- errorString: null
280
+ errorString: null,
283
281
  };
284
282
  if (!formulaRPN)
285
283
  return calculationResult;
@@ -289,7 +287,7 @@ export class Parser {
289
287
  if (!this.allowedOperators.has(frontItem)) {
290
288
  const [sign, variableKey] = /^[+-]/.test(frontItem) ? [frontItem[0], frontItem.slice(1)] : ["", frontItem];
291
289
  const operandValue = Number.parseFloat(this.variables.get(variableKey)?.toString() ?? variableKey);
292
- const number = Number.parseFloat(`${sign}1`) * operandValue;
290
+ const number = Number.parseFloat(sign + "1") * operandValue;
293
291
  calcStack.push(Big(number));
294
292
  }
295
293
  else {
@@ -323,7 +321,7 @@ export class Parser {
323
321
  }
324
322
  }
325
323
  catch (error) {
326
- calculationResult.errorString = error instanceof Error ? error.message : "Unknown error during calculation";
324
+ calculationResult.errorString = error;
327
325
  return calculationResult;
328
326
  }
329
327
  }
@@ -332,8 +330,7 @@ export class Parser {
332
330
  calculationResult.errorString = "Calculation error: Empty result stack";
333
331
  return calculationResult;
334
332
  }
335
- const topValue = calcStack.top();
336
- calculationResult.result = topValue !== undefined ? parseFloat(topValue.toString()) : undefined;
333
+ calculationResult.result = parseFloat(calcStack.top().toString());
337
334
  return calculationResult;
338
335
  }
339
336
  }
@@ -1,7 +1,9 @@
1
1
  export class Queue {
2
- _elements = {};
3
- _head = 0;
4
- _tail = 0;
2
+ constructor() {
3
+ this._elements = {};
4
+ this._head = 0;
5
+ this._tail = 0;
6
+ }
5
7
  enqueue(item) {
6
8
  this._elements[this._tail] = item;
7
9
  this._tail++;
@@ -1,7 +1,5 @@
1
1
  import { matchSorter } from "match-sorter";
2
2
  export class Recommender {
3
- _wordLimitForSuggestions;
4
- variableList;
5
3
  constructor(variables, minSuggestionLen) {
6
4
  this._wordLimitForSuggestions = minSuggestionLen > 0 ? minSuggestionLen : 1;
7
5
  this.variableList = variables;
@@ -1,5 +1,7 @@
1
1
  export class Stack {
2
- _elements = [];
2
+ constructor() {
3
+ this._elements = [];
4
+ }
3
5
  push(item) {
4
6
  this._elements.push(item);
5
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fw-components/formula-editor",
3
- "version": "2.3.4-linting.0",
3
+ "version": "2.3.4-notion-update.0",
4
4
  "description": "A WYSIWYG type formula editor",
5
5
  "main": "dist/formula-editor/src/formula-editor.js",
6
6
  "exports": {
@@ -13,21 +13,27 @@
13
13
  "access": "public"
14
14
  },
15
15
  "scripts": {
16
+ "start": "es-dev-server --app-index ../../index.html --node-resolve --watch --open",
16
17
  "build": "tsc --composite false",
17
18
  "dev": "tsc -w --composite false",
18
19
  "prepublishOnly": "npm run build"
19
20
  },
20
21
  "dependencies": {
21
- "@fw-components/styles": "^2.3.4-linting.0",
22
- "big.js": "^7.0.1",
23
- "lit": "^3.3.1",
24
- "match-sorter": "^8.1.0",
25
- "typescript": "^5.9.3"
22
+ "@fw-components/styles": "^2.3.4-notion-update.0",
23
+ "big.js": "^6.2.1",
24
+ "lit": "^2.1.2",
25
+ "match-sorter": "^8.0.0",
26
+ "typescript": "^5.0.4"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/fundwave/fw-components"
26
31
  },
27
32
  "author": "The Fundwave Authors",
28
33
  "license": "ISC",
29
34
  "devDependencies": {
30
- "@types/big.js": "^6.2.2"
35
+ "@types/big.js": "^6.1.6",
36
+ "es-dev-server": "^2.1.0"
31
37
  },
32
- "gitHead": "d3ffaee5f92e119b0a93114e1753021065271a67"
38
+ "gitHead": "8c066ab176741959347040fdd45b9bf3906a55f8"
33
39
  }
package/tsconfig.json CHANGED
@@ -1,9 +1,20 @@
1
1
  {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "rootDir": "src",
5
- "outDir": "./dist",
6
- "allowJs": true
7
- },
8
- "include": ["src"]
9
- }
2
+ "compilerOptions": {
3
+ "experimentalDecorators": true,
4
+ "useDefineForClassFields":false,
5
+ "outDir": "./dist",
6
+ "rootDir": "../",
7
+ "target": "esnext",
8
+ "module": "esnext",
9
+ "moduleResolution": "node",
10
+ "declaration": true,
11
+ "declarationDir": "./dist/types",
12
+ "composite": false,
13
+ "lib": ["esnext", "dom"],
14
+ "esModuleInterop": true,
15
+ "skipLibCheck": true,
16
+ "noEmitOnError": false
17
+ },
18
+ "include": ["src/**/*.ts"],
19
+ "exclude": ["node_modules", "dist"]
20
+ }