kmap-term-tree 0.9.21 → 1.0.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.
Files changed (37) hide show
  1. package/demo/index.html +124 -10
  2. package/demo/kmap.html +64 -0
  3. package/dist/src/KmapTermTree.d.ts +37 -46
  4. package/dist/src/KmapTermTree.js +641 -216
  5. package/dist/src/KmapTermTree.js.map +1 -1
  6. package/dist/src/asciimath-parser.d.ts +17 -0
  7. package/dist/src/asciimath-parser.js +472 -0
  8. package/dist/src/asciimath-parser.js.map +1 -0
  9. package/dist/src/index.d.ts +2 -0
  10. package/dist/src/index.js +2 -0
  11. package/dist/src/index.js.map +1 -1
  12. package/dist/src/katex-css.d.ts +2 -0
  13. package/dist/src/katex-css.js +7 -0
  14. package/dist/src/katex-css.js.map +1 -0
  15. package/dist/src/model.d.ts +30 -0
  16. package/dist/src/model.js +26 -0
  17. package/dist/src/model.js.map +1 -0
  18. package/dist/src/parser.js.map +1 -1
  19. package/dist/src/tokenizer.js.map +1 -1
  20. package/dist/stories/index.stories.d.ts +20 -0
  21. package/dist/stories/index.stories.js +26 -2
  22. package/dist/stories/index.stories.js.map +1 -1
  23. package/dist/test/asciimath-parser.test.d.ts +1 -0
  24. package/dist/test/asciimath-parser.test.js +45 -0
  25. package/dist/test/asciimath-parser.test.js.map +1 -0
  26. package/dist/test/kmap-term-tree.test.js +45 -8
  27. package/dist/test/kmap-term-tree.test.js.map +1 -1
  28. package/dist/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +16 -50
  30. package/src/KmapTermTree.ts +675 -230
  31. package/src/asciimath-parser.ts +554 -0
  32. package/src/index.ts +2 -0
  33. package/src/katex-css.ts +7 -0
  34. package/src/model.ts +57 -0
  35. package/stories/index.stories.ts +35 -2
  36. package/test/asciimath-parser.test.ts +50 -0
  37. package/test/kmap-term-tree.test.ts +66 -7
@@ -6,6 +6,9 @@ export default {
6
6
  component: 'kmap-term-tree',
7
7
  argTypes: {
8
8
  term: { control: 'text' },
9
+ showLabels: { control: 'boolean' },
10
+ showDetails: { control: 'boolean' },
11
+ tension: { control: { type: 'range', min: 0, max: 1, step: 0.05 } },
9
12
  textColor: { control: 'color' },
10
13
  backgroundColor: { control: 'color' },
11
14
  borderColor: { control: 'color' },
@@ -21,6 +24,9 @@ interface Story<T> {
21
24
 
22
25
  interface ArgTypes {
23
26
  term?: string;
27
+ showLabels?: boolean;
28
+ showDetails?: boolean;
29
+ tension?: number;
24
30
  textColor?: string;
25
31
  backgroundColor?: string;
26
32
  borderColor?: string;
@@ -28,17 +34,44 @@ interface ArgTypes {
28
34
  }
29
35
 
30
36
  const Template: Story<ArgTypes> = ({
31
- term = '2a+sin(3b)',
37
+ term = '(2+a)(3-b)',
38
+ showLabels = false,
39
+ showDetails = true,
40
+ tension = 0.5,
32
41
  textColor,
33
42
  backgroundColor,
34
43
  borderColor,
35
44
  edgeColor,
36
45
  }: ArgTypes) => html`
37
46
  <kmap-term-tree
38
- style="--kmap-term-tree-text-color: ${textColor || 'black'}; --kmap-term-tree-background-color: ${backgroundColor || 'white'}; --kmap-term-tree-border-color: ${borderColor || '#005b9f'}; --kmap-term-tree-edge-color: ${edgeColor || '#fbc02d'};"
47
+ style="--kmap-term-tree-text-color: ${textColor ||
48
+ '#1f2937'}; --kmap-term-tree-background-color: ${backgroundColor ||
49
+ '#ffffff'}; --kmap-term-tree-border-color: ${borderColor ||
50
+ '#005b9f'}; --kmap-term-tree-edge-color: ${edgeColor || '#cbd5e1'};"
39
51
  .term=${term}
52
+ .showLabels=${showLabels}
53
+ .showDetails=${showDetails}
54
+ .tension=${tension}
40
55
  >
41
56
  </kmap-term-tree>
42
57
  `;
43
58
 
44
59
  export const Regular = Template.bind({});
60
+ Regular.args = {
61
+ term: '(2+a)(3-b)',
62
+ };
63
+
64
+ export const Fraction = Template.bind({});
65
+ Fraction.args = {
66
+ term: '(a+b)/(c+d)',
67
+ };
68
+
69
+ export const Trigonometry = Template.bind({});
70
+ Trigonometry.args = {
71
+ term: '2a + sin(3b)',
72
+ };
73
+
74
+ export const Mitternachtsformel = Template.bind({});
75
+ Mitternachtsformel.args = {
76
+ term: 'sqrt(b^2 - 4ac)',
77
+ };
@@ -0,0 +1,50 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { parseAsciiMath } from '../src/asciimath-parser.js';
3
+
4
+ describe('asciimath-parser', () => {
5
+ it('parses addition and variables', () => {
6
+ const ast = parseAsciiMath('2a + 3b');
7
+ expect(ast.op).to.equal('Add');
8
+ expect(ast.mathJson).to.deep.equal([
9
+ 'Add',
10
+ ['Multiply', 2, 'a'],
11
+ ['Multiply', 3, 'b'],
12
+ ]);
13
+ expect(ast.depth).to.equal(2);
14
+ });
15
+
16
+ it('handles implicit multiplication with parentheses', () => {
17
+ const ast = parseAsciiMath('(2+a)(3-b)');
18
+ expect(ast.op).to.equal('Multiply');
19
+ expect(ast.mathJson).to.deep.equal([
20
+ 'Multiply',
21
+ ['Add', 2, 'a'],
22
+ ['Subtract', 3, 'b'],
23
+ ]);
24
+ expect(ast.depth).to.equal(2);
25
+ });
26
+
27
+ it('handles unary minus and double minus', () => {
28
+ const ast1 = parseAsciiMath('-3 * x');
29
+ expect(ast1.op).to.equal('Multiply');
30
+ expect(ast1.mathJson).to.deep.equal(['Multiply', ['Negate', 3], 'x']);
31
+
32
+ const ast2 = parseAsciiMath('5 - -2');
33
+ expect(ast2.op).to.equal('Subtract');
34
+ expect(ast2.mathJson).to.deep.equal(['Subtract', 5, ['Negate', 2]]);
35
+ });
36
+
37
+ it('handles powers and functions', () => {
38
+ const ast = parseAsciiMath('x^2 + sin(3x)');
39
+ expect(ast.op).to.equal('Add');
40
+ expect(ast.children[0].op).to.equal('Power');
41
+ expect(ast.children[1].op).to.equal('Sin');
42
+ });
43
+
44
+ it('handles division / fraction', () => {
45
+ const ast = parseAsciiMath('(a + b) / (c + d)');
46
+ expect(ast.op).to.equal('Divide');
47
+ expect(ast.children[0].op).to.equal('Add');
48
+ expect(ast.children[1].op).to.equal('Add');
49
+ });
50
+ });
@@ -4,16 +4,75 @@ import { KmapTermTree } from '../src/KmapTermTree.js';
4
4
  import '../src/kmap-term-tree.js';
5
5
 
6
6
  describe('KmapTermTree', () => {
7
- it('has a default title "Hey there" and counter 5', async () => {
8
- const el = await fixture<KmapTermTree>(html`<kmap-term-tree></kmap-term-tree>`);
7
+ it('renders a term with KaTeX and tree nodes', async () => {
8
+ const el = await fixture<KmapTermTree>(
9
+ html`<kmap-term-tree term="2a+3b"></kmap-term-tree>`
10
+ );
11
+ await el.updateComplete;
9
12
 
10
- expect(el.title).to.equal('Hey there');
11
- //expect(el.counter).to.equal(5);
13
+ const formula = el.shadowRoot!.querySelector('#formula');
14
+ expect(formula).to.exist;
15
+ expect(formula!.innerHTML).to.contain('katex');
16
+
17
+ const nodes = el.shadowRoot!.querySelectorAll('.tree-node');
18
+ // For 2a + 3b: nodes are +, and two implicit multiplications (3 operations)
19
+ expect(nodes.length).to.be.greaterThan(0);
20
+ });
21
+
22
+ it('supports slot content', async () => {
23
+ const el = await fixture<KmapTermTree>(
24
+ html`<kmap-term-tree>(2+a)(3-b)</kmap-term-tree>`
25
+ );
26
+ await el.updateComplete;
27
+
28
+ expect(el.term).to.equal('(2+a)(3-b)');
29
+ const formula = el.shadowRoot!.querySelector('#formula');
30
+ expect(formula!.innerHTML).to.contain('katex');
31
+ });
32
+
33
+ it('highlights full height for fractions and roots', async () => {
34
+ const el = await fixture<KmapTermTree>(
35
+ html`<kmap-term-tree term="sqrt(2/3)"></kmap-term-tree>`
36
+ );
37
+ await el.updateComplete;
38
+
39
+ const overlay = el.shadowRoot!.querySelector(
40
+ '.highlight-overlay'
41
+ ) as HTMLElement;
42
+ expect(overlay).to.exist;
43
+
44
+ const overlayRect = overlay.getBoundingClientRect();
45
+ const n1 = el.shadowRoot!.getElementById('n1')!; // numerator 2
46
+ const n2 = el.shadowRoot!.getElementById('n2')!; // denominator 3
47
+
48
+ const r1 = n1.getBoundingClientRect();
49
+ const r2 = n2.getBoundingClientRect();
50
+
51
+ // The overlay top must be at or above the numerator top
52
+ expect(overlayRect.top).to.be.at.most(r1.top);
53
+ // The overlay bottom must be at or below the denominator bottom
54
+ expect(overlayRect.bottom).to.be.at.least(r2.bottom);
12
55
  });
13
56
 
14
- it('passes the a11y audit', async () => {
15
- const el = await fixture<KmapTermTree>(html`<kmap-term-tree></kmap-term-tree>`);
57
+ it('computes correct layout even with CSS scale transform', async () => {
58
+ const el = await fixture<KmapTermTree>(
59
+ html`<kmap-term-tree term="2a+3b"></kmap-term-tree>`
60
+ );
61
+ await el.updateComplete;
62
+
63
+ const normalNode = el.shadowRoot!.querySelector('.tree-node') as HTMLElement;
64
+ expect(normalNode).to.exist;
65
+ const normalLeft = parseFloat(normalNode.style.left);
16
66
 
17
- await expect(el).shadowDom.to.be.accessible();
67
+ // Apply scale transform and recalculate layout
68
+ el.style.transform = 'scale(0.3)';
69
+ (el as any).recalculateLayout();
70
+
71
+ const scaledNode = el.shadowRoot!.querySelector('.tree-node') as HTMLElement;
72
+ const scaledLeft = parseFloat(scaledNode.style.left);
73
+
74
+ // Both should compute substantially the same local canvas left coordinate (within 2px)
75
+ expect(Math.abs(scaledLeft - normalLeft)).to.be.below(2);
18
76
  });
19
77
  });
78
+