react-cheminfo 0.6.0 → 0.7.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 (79) hide show
  1. package/README.md +16 -0
  2. package/lib/citation/core/index.d.ts +1 -0
  3. package/lib/citation/core/index.d.ts.map +1 -1
  4. package/lib/citation/core/index.js +1 -0
  5. package/lib/citation/core/index.js.map +1 -1
  6. package/lib/citation/core/platformPaper.d.ts +14 -0
  7. package/lib/citation/core/platformPaper.d.ts.map +1 -0
  8. package/lib/citation/core/platformPaper.js +28 -0
  9. package/lib/citation/core/platformPaper.js.map +1 -0
  10. package/lib/color/core/index.d.ts +1 -1
  11. package/lib/color/core/index.d.ts.map +1 -1
  12. package/lib/color/core/index.js +1 -1
  13. package/lib/color/core/index.js.map +1 -1
  14. package/lib/core.d.ts +1 -0
  15. package/lib/core.d.ts.map +1 -1
  16. package/lib/core.js +1 -0
  17. package/lib/core.js.map +1 -1
  18. package/lib/ecosystem/core/sites.js +5 -5
  19. package/lib/orbital/core/index.d.ts +1 -1
  20. package/lib/orbital/core/index.d.ts.map +1 -1
  21. package/lib/orbital/core/index.js +1 -1
  22. package/lib/orbital/core/index.js.map +1 -1
  23. package/lib/periodic/core/categories.d.ts +25 -0
  24. package/lib/periodic/core/categories.d.ts.map +1 -0
  25. package/lib/periodic/core/categories.js +70 -0
  26. package/lib/periodic/core/categories.js.map +1 -0
  27. package/lib/periodic/core/elements.d.ts +49 -0
  28. package/lib/periodic/core/elements.d.ts.map +1 -0
  29. package/lib/periodic/core/elements.js +175 -0
  30. package/lib/periodic/core/elements.js.map +1 -0
  31. package/lib/periodic/core/index.d.ts +6 -0
  32. package/lib/periodic/core/index.d.ts.map +1 -0
  33. package/lib/periodic/core/index.js +4 -0
  34. package/lib/periodic/core/index.js.map +1 -0
  35. package/lib/periodic/core/layout.d.ts +73 -0
  36. package/lib/periodic/core/layout.d.ts.map +1 -0
  37. package/lib/periodic/core/layout.js +132 -0
  38. package/lib/periodic/core/layout.js.map +1 -0
  39. package/lib/periodic/ui/CategoryLegend.d.ts +26 -0
  40. package/lib/periodic/ui/CategoryLegend.d.ts.map +1 -0
  41. package/lib/periodic/ui/CategoryLegend.js +53 -0
  42. package/lib/periodic/ui/CategoryLegend.js.map +1 -0
  43. package/lib/periodic/ui/ElementCell.d.ts +53 -0
  44. package/lib/periodic/ui/ElementCell.d.ts.map +1 -0
  45. package/lib/periodic/ui/ElementCell.js +56 -0
  46. package/lib/periodic/ui/ElementCell.js.map +1 -0
  47. package/lib/periodic/ui/PeriodicTable.d.ts +90 -0
  48. package/lib/periodic/ui/PeriodicTable.d.ts.map +1 -0
  49. package/lib/periodic/ui/PeriodicTable.js +77 -0
  50. package/lib/periodic/ui/PeriodicTable.js.map +1 -0
  51. package/lib/periodic/ui/PeriodicTableChrome.d.ts +36 -0
  52. package/lib/periodic/ui/PeriodicTableChrome.d.ts.map +1 -0
  53. package/lib/periodic/ui/PeriodicTableChrome.js +72 -0
  54. package/lib/periodic/ui/PeriodicTableChrome.js.map +1 -0
  55. package/lib/periodic/ui/index.d.ts +7 -0
  56. package/lib/periodic/ui/index.d.ts.map +1 -0
  57. package/lib/periodic/ui/index.js +4 -0
  58. package/lib/periodic/ui/index.js.map +1 -0
  59. package/lib/ui.d.ts +1 -0
  60. package/lib/ui.d.ts.map +1 -1
  61. package/lib/ui.js +1 -0
  62. package/lib/ui.js.map +1 -1
  63. package/package.json +2 -1
  64. package/src/citation/core/index.ts +1 -0
  65. package/src/citation/core/platformPaper.ts +32 -0
  66. package/src/color/core/index.ts +6 -1
  67. package/src/core.ts +1 -0
  68. package/src/ecosystem/core/sites.ts +5 -5
  69. package/src/orbital/core/index.ts +1 -1
  70. package/src/periodic/core/categories.ts +83 -0
  71. package/src/periodic/core/elements.ts +217 -0
  72. package/src/periodic/core/index.ts +27 -0
  73. package/src/periodic/core/layout.ts +183 -0
  74. package/src/periodic/ui/CategoryLegend.tsx +105 -0
  75. package/src/periodic/ui/ElementCell.tsx +137 -0
  76. package/src/periodic/ui/PeriodicTable.tsx +226 -0
  77. package/src/periodic/ui/PeriodicTableChrome.tsx +170 -0
  78. package/src/periodic/ui/index.ts +6 -0
  79. package/src/ui.ts +1 -0
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Where every element is drawn.
3
+ *
4
+ * The group and the period place the main block, but not the lanthanoids and
5
+ * the actinoids: those have no group, and are drawn on the two rows underneath.
6
+ * The grid is therefore 18 columns by 10 rows — seven periods, a blank spacer,
7
+ * and the two inner-transition rows.
8
+ *
9
+ * The cells here are the *logical* ones, so column 1 is group 1 and row 1 is
10
+ * period 1. A table drawn with the group and period header strips offsets them
11
+ * by one; nothing in this module needs to know that.
12
+ */
13
+ import type { ElementCategory, PeriodicElement } from './elements.ts';
14
+ /** A whole run of the table: one group, or one period. */
15
+ export interface ElementRange {
16
+ kind: 'group' | 'period';
17
+ value: number;
18
+ }
19
+ /** A cell of the grid, one-based as CSS grid lines are. */
20
+ export interface Cell {
21
+ column: number;
22
+ row: number;
23
+ }
24
+ /** Columns of the table. */
25
+ export declare const COLUMN_COUNT = 18;
26
+ /** Rows of the table, the blank spacer between the blocks included. */
27
+ export declare const ROW_COUNT = 10;
28
+ /**
29
+ * The cell an element occupies.
30
+ * @param element - Element to place.
31
+ * @returns Its column and row, both one-based.
32
+ */
33
+ export declare function cellOf(element: PeriodicElement): Cell;
34
+ /**
35
+ * Every element with the cell it occupies, in reading order.
36
+ * @returns One entry per element, ordered by row then column, so a keyboard
37
+ * walk over the list moves the way the eye does.
38
+ */
39
+ export declare function placedElements(): ReadonlyArray<{
40
+ element: PeriodicElement;
41
+ cell: Cell;
42
+ }>;
43
+ /**
44
+ * The two cells the lanthanoids and the actinoids were lifted out of.
45
+ *
46
+ * Without them the main block has a hole in it and the two rows underneath
47
+ * belong nowhere; with them the reader can see where each series was taken
48
+ * from.
49
+ */
50
+ export declare const INNER_TRANSITION_MARKERS: ReadonlyArray<{
51
+ cell: Cell;
52
+ label: string;
53
+ category: ElementCategory;
54
+ }>;
55
+ /** The period each inner-transition row belongs to, for its row label. */
56
+ export declare const INNER_TRANSITION_ROWS: ReadonlyArray<{
57
+ row: number;
58
+ period: number;
59
+ }>;
60
+ /**
61
+ * The element an arrow key walks to.
62
+ *
63
+ * The walk follows the grid, not the atomic number: down from carbon is
64
+ * silicon, the cell underneath it, and a step of 18 protons would instead be
65
+ * chromium because period 2 holds only eight elements. Left and right follow
66
+ * reading order, so the end of a period continues at the start of the next one
67
+ * and the two inner-transition rows come after the main block.
68
+ * @param key - The pressed key, as `KeyboardEvent.key` reports it.
69
+ * @param from - Symbol the walk starts at; any arrow lands on hydrogen when it names no element.
70
+ * @returns The element to move to, or `null` when the key is not an arrow or the table has no cell that way.
71
+ */
72
+ export declare function elementByArrowKey(key: string, from: string | undefined): PeriodicElement | null;
73
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/periodic/core/layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGtE,0DAA0D;AAC1D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,2DAA2D;AAC3D,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,4BAA4B;AAC5B,eAAO,MAAM,YAAY,KAAK,CAAC;AAE/B,uEAAuE;AACvE,eAAO,MAAM,SAAS,KAAK,CAAC;AAc5B;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAIrD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,aAAa,CAAC;IAC9C,OAAO,EAAE,eAAe,CAAC;IACzB,IAAI,EAAE,IAAI,CAAC;CACZ,CAAC,CAUD;AAKD;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,EAAE,aAAa,CAAC;IACnD,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,CAAC;CAC3B,CAGA,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB,CAGA,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,eAAe,GAAG,IAAI,CAgBxB"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Where every element is drawn.
3
+ *
4
+ * The group and the period place the main block, but not the lanthanoids and
5
+ * the actinoids: those have no group, and are drawn on the two rows underneath.
6
+ * The grid is therefore 18 columns by 10 rows — seven periods, a blank spacer,
7
+ * and the two inner-transition rows.
8
+ *
9
+ * The cells here are the *logical* ones, so column 1 is group 1 and row 1 is
10
+ * period 1. A table drawn with the group and period header strips offsets them
11
+ * by one; nothing in this module needs to know that.
12
+ */
13
+ import { PERIODIC_ELEMENTS, elementBySymbol } from "./elements.js";
14
+ /** Columns of the table. */
15
+ export const COLUMN_COUNT = 18;
16
+ /** Rows of the table, the blank spacer between the blocks included. */
17
+ export const ROW_COUNT = 10;
18
+ /** Row the lanthanoids are drawn on, and the actinoids on the one below. */
19
+ const INNER_TRANSITION_ROW = 9;
20
+ /** Atomic number the lanthanoids and the actinoids start at. */
21
+ const INNER_TRANSITION_STARTS = [57, 89];
22
+ /** How many elements each inner-transition series holds. */
23
+ const INNER_TRANSITION_LENGTH = 15;
24
+ /** Column the inner-transition rows start at, under the d block. */
25
+ const INNER_TRANSITION_COLUMN = 3;
26
+ /**
27
+ * The cell an element occupies.
28
+ * @param element - Element to place.
29
+ * @returns Its column and row, both one-based.
30
+ */
31
+ export function cellOf(element) {
32
+ const inner = innerTransitionCell(element);
33
+ if (inner !== null)
34
+ return inner;
35
+ return { column: element.group ?? 1, row: element.period };
36
+ }
37
+ /**
38
+ * Every element with the cell it occupies, in reading order.
39
+ * @returns One entry per element, ordered by row then column, so a keyboard
40
+ * walk over the list moves the way the eye does.
41
+ */
42
+ export function placedElements() {
43
+ PLACED ??= PERIODIC_ELEMENTS.map((element) => ({
44
+ element,
45
+ cell: cellOf(element),
46
+ })).toSorted((first, second) => first.cell.row === second.cell.row
47
+ ? first.cell.column - second.cell.column
48
+ : first.cell.row - second.cell.row);
49
+ return PLACED;
50
+ }
51
+ let PLACED = null;
52
+ /**
53
+ * The two cells the lanthanoids and the actinoids were lifted out of.
54
+ *
55
+ * Without them the main block has a hole in it and the two rows underneath
56
+ * belong nowhere; with them the reader can see where each series was taken
57
+ * from.
58
+ */
59
+ export const INNER_TRANSITION_MARKERS = [
60
+ { cell: { column: 3, row: 6 }, label: '57–71', category: 'lanthanoid' },
61
+ { cell: { column: 3, row: 7 }, label: '89–103', category: 'actinoid' },
62
+ ];
63
+ /** The period each inner-transition row belongs to, for its row label. */
64
+ export const INNER_TRANSITION_ROWS = [
65
+ { row: INNER_TRANSITION_ROW, period: 6 },
66
+ { row: INNER_TRANSITION_ROW + 1, period: 7 },
67
+ ];
68
+ /**
69
+ * The element an arrow key walks to.
70
+ *
71
+ * The walk follows the grid, not the atomic number: down from carbon is
72
+ * silicon, the cell underneath it, and a step of 18 protons would instead be
73
+ * chromium because period 2 holds only eight elements. Left and right follow
74
+ * reading order, so the end of a period continues at the start of the next one
75
+ * and the two inner-transition rows come after the main block.
76
+ * @param key - The pressed key, as `KeyboardEvent.key` reports it.
77
+ * @param from - Symbol the walk starts at; any arrow lands on hydrogen when it names no element.
78
+ * @returns The element to move to, or `null` when the key is not an arrow or the table has no cell that way.
79
+ */
80
+ export function elementByArrowKey(key, from) {
81
+ const direction = ARROW_DIRECTIONS[key];
82
+ if (direction === undefined)
83
+ return null;
84
+ const placed = placedElements();
85
+ const start = from === undefined ? undefined : elementBySymbol(from);
86
+ if (start === undefined)
87
+ return placed[0]?.element ?? null;
88
+ if (direction.column !== 0) {
89
+ const index = readingOrderIndex().get(start.symbol);
90
+ if (index === undefined)
91
+ return null;
92
+ return placed[index + direction.column]?.element ?? null;
93
+ }
94
+ const cell = cellOf(start);
95
+ return byCell().get(cellKey(cell.column, cell.row + direction.row)) ?? null;
96
+ }
97
+ /** Which way each arrow key moves, in grid cells. */
98
+ const ARROW_DIRECTIONS = {
99
+ ArrowRight: { column: 1, row: 0 },
100
+ ArrowLeft: { column: -1, row: 0 },
101
+ ArrowDown: { column: 0, row: 1 },
102
+ ArrowUp: { column: 0, row: -1 },
103
+ };
104
+ function readingOrderIndex() {
105
+ READING_ORDER ??= new Map(placedElements().map(({ element }, index) => [element.symbol, index]));
106
+ return READING_ORDER;
107
+ }
108
+ let READING_ORDER = null;
109
+ function byCell() {
110
+ BY_CELL ??= new Map(placedElements().map(({ element, cell }) => [
111
+ cellKey(cell.column, cell.row),
112
+ element,
113
+ ]));
114
+ return BY_CELL;
115
+ }
116
+ let BY_CELL = null;
117
+ function cellKey(column, row) {
118
+ return `${String(column)}:${String(row)}`;
119
+ }
120
+ function innerTransitionCell(element) {
121
+ for (const [index, start] of INNER_TRANSITION_STARTS.entries()) {
122
+ const offset = element.atomicNumber - start;
123
+ if (offset >= 0 && offset < INNER_TRANSITION_LENGTH) {
124
+ return {
125
+ column: INNER_TRANSITION_COLUMN + offset,
126
+ row: INNER_TRANSITION_ROW + index,
127
+ };
128
+ }
129
+ }
130
+ return null;
131
+ }
132
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/periodic/core/layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The key to the family colours, under the table.
3
+ */
4
+ import type { ReactElement } from 'react';
5
+ import type { ElementCategory } from '../core/elements.ts';
6
+ /** What {@link CategoryLegend} needs. */
7
+ export interface CategoryLegendProps {
8
+ /**
9
+ * Called with the family whose swatch was clicked. Without it the legend is
10
+ * a key rather than a control, and nothing in it is focusable.
11
+ * @default undefined
12
+ */
13
+ onSelect?: (category: ElementCategory) => void;
14
+ /**
15
+ * The family drawn as the active one.
16
+ * @default undefined — none is
17
+ */
18
+ selected?: ElementCategory;
19
+ }
20
+ /**
21
+ * The ten families, each with its colour.
22
+ * @param props - See {@link CategoryLegendProps}.
23
+ * @returns The legend.
24
+ */
25
+ export declare function CategoryLegend(props: CategoryLegendProps): ReactElement;
26
+ //# sourceMappingURL=CategoryLegend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CategoryLegend.d.ts","sourceRoot":"","sources":["../../../src/periodic/ui/CategoryLegend.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAC;AAOzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,yCAAyC;AACzC,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,IAAI,CAAC;IAC/C;;;OAGG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,YAAY,CAwCvE"}
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { CATEGORY_LABELS, CATEGORY_ORDER, categorySwatch, } from "../core/categories.js";
3
+ /**
4
+ * The ten families, each with its colour.
5
+ * @param props - See {@link CategoryLegendProps}.
6
+ * @returns The legend.
7
+ */
8
+ export function CategoryLegend(props) {
9
+ const { onSelect, selected } = props;
10
+ return (_jsx("div", { style: legendStyle, children: CATEGORY_ORDER.map((category) => {
11
+ const swatch = categorySwatch(category);
12
+ const label = CATEGORY_LABELS[category];
13
+ const mark = (_jsx("span", { style: { ...swatchStyle, background: swatch.background } }));
14
+ if (onSelect === undefined) {
15
+ return (_jsxs("span", { style: itemStyle, children: [mark, label] }, category));
16
+ }
17
+ return (_jsxs("button", { type: "button", "aria-pressed": category === selected, onClick: () => {
18
+ onSelect(category);
19
+ }, style: {
20
+ ...itemStyle,
21
+ ...buttonStyle,
22
+ fontWeight: category === selected ? 700 : 400,
23
+ }, children: [mark, label] }, category));
24
+ }) }));
25
+ }
26
+ const legendStyle = {
27
+ color: 'rgb(95 107 124)',
28
+ display: 'flex',
29
+ flexWrap: 'wrap',
30
+ fontSize: 11,
31
+ gap: '2px 10px',
32
+ };
33
+ const itemStyle = {
34
+ alignItems: 'center',
35
+ display: 'inline-flex',
36
+ gap: 4,
37
+ };
38
+ const buttonStyle = {
39
+ background: 'none',
40
+ border: 'none',
41
+ color: 'inherit',
42
+ cursor: 'pointer',
43
+ font: 'inherit',
44
+ padding: 0,
45
+ };
46
+ const swatchStyle = {
47
+ border: '1px solid rgb(255 255 255 / 0.55)',
48
+ borderRadius: 2,
49
+ display: 'inline-block',
50
+ height: 10,
51
+ width: 10,
52
+ };
53
+ //# sourceMappingURL=CategoryLegend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CategoryLegend.js","sourceRoot":"","sources":["../../../src/periodic/ui/CategoryLegend.tsx"],"names":[],"mappings":";AAMA,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,GACf,MAAM,uBAAuB,CAAC;AAkB/B;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAA0B;IACvD,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAErC,OAAO,CACL,cAAK,KAAK,EAAE,WAAW,YACpB,cAAc,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;YAC/B,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;YACxC,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;YACxC,MAAM,IAAI,GAAG,CACX,eAAM,KAAK,EAAE,EAAE,GAAG,WAAW,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,GAAI,CACnE,CAAC;YACF,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,OAAO,CACL,gBAAqB,KAAK,EAAE,SAAS,aAClC,IAAI,EACJ,KAAK,KAFG,QAAQ,CAGZ,CACR,CAAC;YACJ,CAAC;YACD,OAAO,CACL,kBAEE,IAAI,EAAC,QAAQ,kBACC,QAAQ,KAAK,QAAQ,EACnC,OAAO,EAAE,GAAG,EAAE;oBACZ,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBACrB,CAAC,EACD,KAAK,EAAE;oBACL,GAAG,SAAS;oBACZ,GAAG,WAAW;oBACd,UAAU,EAAE,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;iBAC9C,aAEA,IAAI,EACJ,KAAK,KAbD,QAAQ,CAcN,CACV,CAAC;QACJ,CAAC,CAAC,GACE,CACP,CAAC;AACJ,CAAC;AAED,MAAM,WAAW,GAAG;IAClB,KAAK,EAAE,iBAAiB;IACxB,OAAO,EAAE,MAAM;IACf,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,EAAE;IACZ,GAAG,EAAE,UAAU;CACiB,CAAC;AAEnC,MAAM,SAAS,GAAG;IAChB,UAAU,EAAE,QAAQ;IACpB,OAAO,EAAE,aAAa;IACtB,GAAG,EAAE,CAAC;CAC0B,CAAC;AAEnC,MAAM,WAAW,GAAG;IAClB,UAAU,EAAE,MAAM;IAClB,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,CAAC;CACsB,CAAC;AAEnC,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,mCAAmC;IAC3C,YAAY,EAAE,CAAC;IACf,OAAO,EAAE,cAAc;IACvB,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;CACuB,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * One cell of the periodic table: the atomic number, the symbol, and whatever
3
+ * the tool asked to be written under it.
4
+ *
5
+ * A cell is a real `<button>`, so Tab reaches it, Enter and Space activate it,
6
+ * and a screen reader reads the element's name rather than its symbol.
7
+ */
8
+ import type { ReactElement } from 'react';
9
+ import type { Swatch } from '../../color/core/scale.ts';
10
+ /** What {@link ElementCell} needs to draw one element. */
11
+ export interface ElementCellProps {
12
+ /** Atomic number, written small in the corner. */
13
+ atomicNumber: number;
14
+ /** Chemical symbol, the largest thing in the cell. */
15
+ symbol: string;
16
+ /** Full name, which is what the cell is announced as. */
17
+ name: string;
18
+ /** Background, and the ink that stays readable on it. */
19
+ swatch: Swatch;
20
+ /** Column of the grid, one-based. */
21
+ column: number;
22
+ /** Row of the grid, one-based. */
23
+ row: number;
24
+ onSelect: (symbol: string) => void;
25
+ /**
26
+ * Third line, under the symbol: the value the tool is showing.
27
+ * @default '' — nothing is written
28
+ */
29
+ detail?: string;
30
+ /**
31
+ * Whether the cell is the one the tools are pointed at.
32
+ * @default false
33
+ */
34
+ isSelected?: boolean;
35
+ /**
36
+ * Whether the cell is inside the set the tool is showing. Everything outside
37
+ * it is dimmed rather than removed, so the table keeps its shape.
38
+ * @default true
39
+ */
40
+ isIncluded?: boolean;
41
+ /**
42
+ * Called on pointer enter with the symbol, and on leave with `null`.
43
+ * @default undefined
44
+ */
45
+ onHover?: (symbol: string | null) => void;
46
+ }
47
+ /**
48
+ * A single element of the table.
49
+ * @param props - See {@link ElementCellProps}.
50
+ * @returns The cell.
51
+ */
52
+ export declare function ElementCell(props: ElementCellProps): ReactElement;
53
+ //# sourceMappingURL=ElementCell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ElementCell.d.ts","sourceRoot":"","sources":["../../../src/periodic/ui/ElementCell.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAExD,0DAA0D;AAC1D,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC3C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CA6CjE"}
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * A single element of the table.
4
+ * @param props - See {@link ElementCellProps}.
5
+ * @returns The cell.
6
+ */
7
+ export function ElementCell(props) {
8
+ const { atomicNumber, symbol, name, swatch, column, row, onSelect, detail = '', isSelected = false, isIncluded = true, onHover, } = props;
9
+ return (_jsxs("button", { type: "button", "data-testid": `element-${symbol}`, "data-symbol": symbol, "aria-label": `${name} (${symbol}, Z = ${String(atomicNumber)})`, "aria-pressed": isSelected, onClick: () => {
10
+ onSelect(symbol);
11
+ }, onPointerEnter: () => onHover?.(symbol), onPointerLeave: () => onHover?.(null), style: {
12
+ ...cellStyle,
13
+ gridColumn: column,
14
+ gridRow: row,
15
+ background: swatch.background,
16
+ color: swatch.foreground,
17
+ opacity: isIncluded ? 1 : 0.28,
18
+ // An outline rather than a fill: a table coloured by a property must
19
+ // keep saying what the value is while a cell is selected.
20
+ outline: isSelected ? `2px solid ${swatch.foreground}` : 'none',
21
+ outlineOffset: -3,
22
+ }, children: [_jsx("span", { style: numberStyle, children: atomicNumber }), _jsx("span", { style: symbolStyle, children: symbol }), detail === '' ? null : _jsx("span", { style: detailStyle, children: detail })] }));
23
+ }
24
+ const cellStyle = {
25
+ alignItems: 'center',
26
+ border: '1px solid rgb(255 255 255 / 0.55)',
27
+ borderRadius: 3,
28
+ cursor: 'pointer',
29
+ display: 'flex',
30
+ flexDirection: 'column',
31
+ font: 'inherit',
32
+ justifyContent: 'center',
33
+ lineHeight: 1.05,
34
+ minWidth: 0,
35
+ overflow: 'hidden',
36
+ padding: 1,
37
+ transition: 'opacity 120ms ease',
38
+ };
39
+ const numberStyle = {
40
+ alignSelf: 'flex-start',
41
+ fontSize: 'clamp(0.34rem, 1.6cqw, 0.5rem)',
42
+ opacity: 0.8,
43
+ paddingLeft: 2,
44
+ };
45
+ const symbolStyle = {
46
+ fontSize: 'clamp(0.55rem, 3.3cqw, 1.05rem)',
47
+ fontWeight: 700,
48
+ };
49
+ const detailStyle = {
50
+ fontSize: 'clamp(0.34rem, 1.6cqw, 0.5rem)',
51
+ maxWidth: '100%',
52
+ overflow: 'hidden',
53
+ textOverflow: 'ellipsis',
54
+ whiteSpace: 'nowrap',
55
+ };
56
+ //# sourceMappingURL=ElementCell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ElementCell.js","sourceRoot":"","sources":["../../../src/periodic/ui/ElementCell.tsx"],"names":[],"mappings":";AAkDA;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,KAAuB;IACjD,MAAM,EACJ,YAAY,EACZ,MAAM,EACN,IAAI,EACJ,MAAM,EACN,MAAM,EACN,GAAG,EACH,QAAQ,EACR,MAAM,GAAG,EAAE,EACX,UAAU,GAAG,KAAK,EAClB,UAAU,GAAG,IAAI,EACjB,OAAO,GACR,GAAG,KAAK,CAAC;IAEV,OAAO,CACL,kBACE,IAAI,EAAC,QAAQ,iBACA,WAAW,MAAM,EAAE,iBACnB,MAAM,gBACP,GAAG,IAAI,KAAK,MAAM,SAAS,MAAM,CAAC,YAAY,CAAC,GAAG,kBAChD,UAAU,EACxB,OAAO,EAAE,GAAG,EAAE;YACZ,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnB,CAAC,EACD,cAAc,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,EACvC,cAAc,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EACrC,KAAK,EAAE;YACL,GAAG,SAAS;YACZ,UAAU,EAAE,MAAM;YAClB,OAAO,EAAE,GAAG;YACZ,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,KAAK,EAAE,MAAM,CAAC,UAAU;YACxB,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;YAC9B,qEAAqE;YACrE,0DAA0D;YAC1D,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,aAAa,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,MAAM;YAC/D,aAAa,EAAE,CAAC,CAAC;SAClB,aAED,eAAM,KAAK,EAAE,WAAW,YAAG,YAAY,GAAQ,EAC/C,eAAM,KAAK,EAAE,WAAW,YAAG,MAAM,GAAQ,EACxC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAM,KAAK,EAAE,WAAW,YAAG,MAAM,GAAQ,IAC1D,CACV,CAAC;AACJ,CAAC;AAED,MAAM,SAAS,GAAG;IAChB,UAAU,EAAE,QAAQ;IACpB,MAAM,EAAE,mCAAmC;IAC3C,YAAY,EAAE,CAAC;IACf,MAAM,EAAE,SAAS;IACjB,OAAO,EAAE,MAAM;IACf,aAAa,EAAE,QAAQ;IACvB,IAAI,EAAE,SAAS;IACf,cAAc,EAAE,QAAQ;IACxB,UAAU,EAAE,IAAI;IAChB,QAAQ,EAAE,CAAC;IACX,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,CAAC;IACV,UAAU,EAAE,oBAAoB;CACA,CAAC;AAEnC,MAAM,WAAW,GAAG;IAClB,SAAS,EAAE,YAAY;IACvB,QAAQ,EAAE,gCAAgC;IAC1C,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,CAAC;CACkB,CAAC;AAEnC,MAAM,WAAW,GAAG;IAClB,QAAQ,EAAE,iCAAiC;IAC3C,UAAU,EAAE,GAAG;CACiB,CAAC;AAEnC,MAAM,WAAW,GAAG;IAClB,QAAQ,EAAE,gCAAgC;IAC1C,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,QAAQ;IAClB,YAAY,EAAE,UAAU;IACxB,UAAU,EAAE,QAAQ;CACY,CAAC"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The periodic table.
3
+ *
4
+ * It knows nothing about what it is showing: the caller says what colour each
5
+ * cell takes and what is written in it, and gets back which element was
6
+ * clicked. That is what lets the same grid be an element picker, a property
7
+ * map, and a chart's selection control.
8
+ *
9
+ * Everything site-specific arrives through a callback keyed on the element, so
10
+ * a site's own richer element record never has to cross into this component.
11
+ */
12
+ import type { ReactElement } from 'react';
13
+ import type { Swatch } from '../../color/core/scale.ts';
14
+ import type { PeriodicElement } from '../core/elements.ts';
15
+ import type { ElementRange } from '../core/layout.ts';
16
+ /** What {@link PeriodicTable} needs. */
17
+ export interface PeriodicTableProps {
18
+ /**
19
+ * Symbol of the element the tools are pointed at.
20
+ * @default undefined — none is
21
+ */
22
+ selected?: string;
23
+ /**
24
+ * Called with the symbol of the element that was clicked, and by the arrow
25
+ * keys.
26
+ * @default undefined — the table is a figure rather than a control
27
+ */
28
+ onSelect?: (symbol: string) => void;
29
+ /**
30
+ * The colour each cell takes.
31
+ * @default the family colour
32
+ */
33
+ swatchOf?: (element: PeriodicElement) => Swatch;
34
+ /**
35
+ * What is written under the symbol; an empty string writes nothing.
36
+ * @default nothing is written
37
+ */
38
+ detailOf?: (element: PeriodicElement) => string;
39
+ /**
40
+ * How an element is named, for the label a screen reader reads. The hook a
41
+ * site translating the table writes its own names through.
42
+ * @default the English name
43
+ */
44
+ nameOf?: (element: PeriodicElement) => string;
45
+ /**
46
+ * Whether an element is inside the set the tool is showing. Everything
47
+ * outside it is dimmed rather than removed, so the table keeps its shape.
48
+ * @default every element is
49
+ */
50
+ isIncluded?: (element: PeriodicElement) => boolean;
51
+ /**
52
+ * Whether to draw the group and period strips.
53
+ * @default false
54
+ */
55
+ headers?: boolean;
56
+ /**
57
+ * Called when a whole group or period header is clicked. Without it the
58
+ * strips are labels rather than buttons.
59
+ * @default undefined
60
+ */
61
+ onSelectRange?: (range: ElementRange) => void;
62
+ /**
63
+ * Whether to draw the family legend under the grid.
64
+ * @default false
65
+ */
66
+ legend?: boolean;
67
+ /**
68
+ * Whether the dashed markers stand where the two inner-transition series were
69
+ * lifted out of the main block.
70
+ * @default true
71
+ */
72
+ markers?: boolean;
73
+ /**
74
+ * Whether the arrow keys walk the table by atomic number.
75
+ * @default true
76
+ */
77
+ keyboard?: boolean;
78
+ /**
79
+ * Called on pointer enter with the symbol, and on leave with `null`.
80
+ * @default undefined
81
+ */
82
+ onHover?: (symbol: string | null) => void;
83
+ }
84
+ /**
85
+ * The 118 elements, laid out as the table.
86
+ * @param props - See {@link PeriodicTableProps}.
87
+ * @returns The grid, its optional chrome, and its optional legend.
88
+ */
89
+ export declare function PeriodicTable(props: PeriodicTableProps): ReactElement;
90
+ //# sourceMappingURL=PeriodicTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PeriodicTable.d.ts","sourceRoot":"","sources":["../../../src/periodic/ui/PeriodicTable.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAgC,YAAY,EAAE,MAAM,OAAO,CAAC;AAGxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAExD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AActD,wCAAwC;AACxC,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,MAAM,CAAC;IAChD;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,MAAM,CAAC;IAChD;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,MAAM,CAAC;IAC9C;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC;IACnD;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC9C;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC3C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,YAAY,CAuErE"}
@@ -0,0 +1,77 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from 'react';
3
+ import { categorySwatch } from "../core/categories.js";
4
+ import { COLUMN_COUNT, elementByArrowKey, placedElements, } from "../core/layout.js";
5
+ import { CategoryLegend } from "./CategoryLegend.js";
6
+ import { ElementCell } from "./ElementCell.js";
7
+ import { HeaderStrips, InnerTransitionMarkers, } from "./PeriodicTableChrome.js";
8
+ /**
9
+ * The 118 elements, laid out as the table.
10
+ * @param props - See {@link PeriodicTableProps}.
11
+ * @returns The grid, its optional chrome, and its optional legend.
12
+ */
13
+ export function PeriodicTable(props) {
14
+ const { selected, onSelect, swatchOf = defaultSwatchOf, detailOf, nameOf = defaultNameOf, isIncluded, headers = false, onSelectRange, legend = false, markers = true, keyboard = true, onHover, } = props;
15
+ const gridRef = useRef(null);
16
+ const cameFromKeyRef = useRef(false);
17
+ const offset = headers ? 1 : 0;
18
+ useEffect(() => {
19
+ if (!cameFromKeyRef.current)
20
+ return;
21
+ cameFromKeyRef.current = false;
22
+ const cell = gridRef.current?.querySelector(`[data-symbol="${CSS.escape(selected ?? '')}"]`);
23
+ cell?.focus();
24
+ cell?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
25
+ }, [selected]);
26
+ function handleKeyDown(event) {
27
+ if (!keyboard || onSelect === undefined)
28
+ return;
29
+ const next = elementByArrowKey(event.key, selected);
30
+ if (next === null)
31
+ return;
32
+ event.preventDefault();
33
+ cameFromKeyRef.current = true;
34
+ onSelect(next.symbol);
35
+ }
36
+ return (_jsxs("div", { style: rootStyle, children: [_jsxs("div", { ref: gridRef, role: "grid", "aria-label": "Periodic table", "data-testid": "periodic-table", style: headers ? gridWithHeadersStyle : gridStyle, onKeyDown: handleKeyDown, children: [headers ? _jsx(HeaderStrips, { onSelectRange: onSelectRange }) : null, markers ? _jsx(InnerTransitionMarkers, { offset: offset }) : null, placedElements().map(({ element, cell }) => (_jsx(ElementCell, { atomicNumber: element.atomicNumber, symbol: element.symbol, name: nameOf(element), detail: detailOf?.(element), swatch: swatchOf(element), isSelected: element.symbol === selected, isIncluded: isIncluded?.(element), column: cell.column + offset, row: cell.row + offset, onSelect: onSelect ?? noop, onHover: onHover }, element.symbol)))] }), legend ? _jsx(CategoryLegend, {}) : null] }));
37
+ }
38
+ function defaultSwatchOf(element) {
39
+ return categorySwatch(element.category);
40
+ }
41
+ function defaultNameOf(element) {
42
+ return element.name;
43
+ }
44
+ function noop() {
45
+ // A table with no `onSelect` is a figure; its cells stay buttons so the
46
+ // keyboard and a screen reader still reach every element.
47
+ }
48
+ const rootStyle = {
49
+ display: 'flex',
50
+ flexDirection: 'column',
51
+ gap: 8,
52
+ };
53
+ const baseGridStyle = {
54
+ display: 'grid',
55
+ gap: 2,
56
+ width: '100%',
57
+ // The cells size their type against this box rather than against the page,
58
+ // so the same table reads at 320px beside a chart and at 900px on its own.
59
+ containerType: 'inline-size',
60
+ };
61
+ const gridStyle = {
62
+ ...baseGridStyle,
63
+ // The eighth row is the gap the inner-transition series are lifted out into.
64
+ gridTemplateColumns: `repeat(${String(COLUMN_COUNT)}, minmax(0, 1fr))`,
65
+ gridTemplateRows: 'repeat(7, minmax(0, 1fr)) 0.5rem repeat(2, minmax(0, 1fr))',
66
+ aspectRatio: `${String(COLUMN_COUNT)} / 9.7`,
67
+ minWidth: 280,
68
+ };
69
+ const gridWithHeadersStyle = {
70
+ ...baseGridStyle,
71
+ // A leading column and a leading row hold the period and group numbers.
72
+ gridTemplateColumns: `1.4rem repeat(${String(COLUMN_COUNT)}, minmax(0, 1fr))`,
73
+ gridTemplateRows: '1rem repeat(7, minmax(0, 1fr)) 0.5rem repeat(2, minmax(0, 1fr))',
74
+ aspectRatio: `${String(COLUMN_COUNT + 1.2)} / 10.6`,
75
+ minWidth: 280,
76
+ };
77
+ //# sourceMappingURL=PeriodicTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PeriodicTable.js","sourceRoot":"","sources":["../../../src/periodic/ui/PeriodicTable.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The furniture around the cells: the group and period strips, and the two
3
+ * markers the inner-transition series were lifted out of.
4
+ */
5
+ import type { ReactElement } from 'react';
6
+ import type { ElementRange } from '../core/layout.ts';
7
+ /** What {@link HeaderStrips} needs. */
8
+ export interface HeaderStripsProps {
9
+ /**
10
+ * Called with the run whose header was clicked. Without it the strips are
11
+ * labels rather than buttons.
12
+ * @default undefined
13
+ */
14
+ onSelectRange?: (range: ElementRange) => void;
15
+ }
16
+ /**
17
+ * The 1–18 strip along the top and the 1–7 strip down the left.
18
+ *
19
+ * They are buttons when the table takes a range: "plot period 3" is one click
20
+ * there and eight on the cells.
21
+ * @param props - See {@link HeaderStripsProps}.
22
+ * @returns The two strips, placed on the grid.
23
+ */
24
+ export declare function HeaderStrips(props: HeaderStripsProps): ReactElement;
25
+ /** What {@link InnerTransitionMarkers} needs. */
26
+ export interface InnerTransitionMarkersProps {
27
+ /** 1 when the table draws its header strips, 0 otherwise. */
28
+ offset: number;
29
+ }
30
+ /**
31
+ * The two cells the lanthanoids and the actinoids were lifted out of.
32
+ * @param props - See {@link InnerTransitionMarkersProps}.
33
+ * @returns The markers, placed on the grid.
34
+ */
35
+ export declare function InnerTransitionMarkers(props: InnerTransitionMarkersProps): ReactElement;
36
+ //# sourceMappingURL=PeriodicTableChrome.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PeriodicTableChrome.d.ts","sourceRoot":"","sources":["../../../src/periodic/ui/PeriodicTableChrome.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAOtD,uCAAuC;AACvC,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CAC/C;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAqDnE;AAED,iDAAiD;AACjD,MAAM,WAAW,2BAA2B;IAC1C,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,2BAA2B,GACjC,YAAY,CAmBd"}