@1771technologies/lytenyte-pro 2.0.4-dev.3 → 2.1.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 (180) hide show
  1. package/README.md +54 -11
  2. package/css/components/expression-editor.css +106 -0
  3. package/dist/components/column-manager/column-manager.d.ts +6 -1
  4. package/dist/components/column-manager/column-manager.js +23 -2
  5. package/dist/components/expressions-editor/create-completion-provider.d.ts +10 -0
  6. package/dist/components/expressions-editor/create-completion-provider.js +391 -0
  7. package/dist/components/expressions-editor/create-key-down-handler.d.ts +18 -0
  8. package/dist/components/expressions-editor/create-key-down-handler.js +49 -0
  9. package/dist/components/expressions-editor/cursor-position/measure-cursor-at-pointer.d.ts +2 -0
  10. package/dist/components/expressions-editor/cursor-position/measure-cursor-at-pointer.js +56 -0
  11. package/dist/components/expressions-editor/cursor-position/use-cursor-position.d.ts +5 -0
  12. package/dist/components/expressions-editor/cursor-position/use-cursor-position.js +33 -0
  13. package/dist/components/expressions-editor/expression-editor.d.ts +3 -0
  14. package/dist/components/expressions-editor/expression-editor.js +158 -0
  15. package/dist/components/expressions-editor/get-indentation.d.ts +1 -0
  16. package/dist/components/expressions-editor/get-indentation.js +7 -0
  17. package/dist/components/expressions-editor/handle-completion-key-down.d.ts +2 -0
  18. package/dist/components/expressions-editor/handle-completion-key-down.js +22 -0
  19. package/dist/components/expressions-editor/handle-enter-key.d.ts +4 -0
  20. package/dist/components/expressions-editor/handle-enter-key.js +11 -0
  21. package/dist/components/expressions-editor/handle-manual-trigger.d.ts +2 -0
  22. package/dist/components/expressions-editor/handle-manual-trigger.js +3 -0
  23. package/dist/components/expressions-editor/index.d.ts +18 -0
  24. package/dist/components/expressions-editor/index.js +11 -0
  25. package/dist/components/expressions-editor/intellisence/completion-context.d.ts +17 -0
  26. package/dist/components/expressions-editor/intellisence/completion-context.js +7 -0
  27. package/dist/components/expressions-editor/intellisence/completion-item.d.ts +5 -0
  28. package/dist/components/expressions-editor/intellisence/completion-item.js +11 -0
  29. package/dist/components/expressions-editor/intellisence/completion-list.d.ts +8 -0
  30. package/dist/components/expressions-editor/intellisence/completion-list.js +18 -0
  31. package/dist/components/expressions-editor/intellisence/completion-popover.d.ts +1 -0
  32. package/dist/components/expressions-editor/intellisence/completion-popover.js +47 -0
  33. package/dist/components/expressions-editor/intellisence/filter-completions-by-prefix.d.ts +2 -0
  34. package/dist/components/expressions-editor/intellisence/filter-completions-by-prefix.js +6 -0
  35. package/dist/components/expressions-editor/intellisence/get-word-at-cursor.d.ts +2 -0
  36. package/dist/components/expressions-editor/intellisence/get-word-at-cursor.js +12 -0
  37. package/dist/components/expressions-editor/intellisence/use-complete-trigger.d.ts +13 -0
  38. package/dist/components/expressions-editor/intellisence/use-complete-trigger.js +41 -0
  39. package/dist/components/expressions-editor/intellisence/use-completions.d.ts +14 -0
  40. package/dist/components/expressions-editor/intellisence/use-completions.js +78 -0
  41. package/dist/components/expressions-editor/replace-word-at-cursor.d.ts +5 -0
  42. package/dist/components/expressions-editor/replace-word-at-cursor.js +7 -0
  43. package/dist/components/expressions-editor/token-highlighter-default.d.ts +4 -0
  44. package/dist/components/expressions-editor/token-highlighter-default.js +20 -0
  45. package/dist/components/expressions-editor/types.d.ts +48 -0
  46. package/dist/components/expressions-editor/types.js +1 -0
  47. package/dist/components/expressions-editor/use-keyboard-navigation.d.ts +10 -0
  48. package/dist/components/expressions-editor/use-keyboard-navigation.js +37 -0
  49. package/dist/components/pill-manager/container.js +55 -9
  50. package/dist/components/pill-manager/item.js +15 -1
  51. package/dist/components/select-all.js +1 -1
  52. package/dist/components/tree-view/root.d.ts +9 -0
  53. package/dist/components/tree-view/root.js +4 -2
  54. package/dist/data-source-client/hooks/use-flattened-groups.js +2 -2
  55. package/dist/expressions/compiler/compile.d.ts +3 -0
  56. package/dist/expressions/compiler/compile.js +4 -0
  57. package/dist/expressions/compiler/eval-constant.d.ts +2 -0
  58. package/dist/expressions/compiler/eval-constant.js +19 -0
  59. package/dist/expressions/compiler/is-constant.d.ts +2 -0
  60. package/dist/expressions/compiler/is-constant.js +6 -0
  61. package/dist/expressions/compiler/make-constant.d.ts +2 -0
  62. package/dist/expressions/compiler/make-constant.js +11 -0
  63. package/dist/expressions/compiler/optimize.d.ts +3 -0
  64. package/dist/expressions/compiler/optimize.js +47 -0
  65. package/dist/expressions/compiler/value-of.d.ts +2 -0
  66. package/dist/expressions/compiler/value-of.js +11 -0
  67. package/dist/expressions/errors/clamp-offset.d.ts +1 -0
  68. package/dist/expressions/errors/clamp-offset.js +3 -0
  69. package/dist/expressions/errors/expression-error.d.ts +10 -0
  70. package/dist/expressions/errors/expression-error.js +19 -0
  71. package/dist/expressions/errors/format-error.d.ts +3 -0
  72. package/dist/expressions/errors/format-error.js +27 -0
  73. package/dist/expressions/errors/get-line-end.d.ts +1 -0
  74. package/dist/expressions/errors/get-line-end.js +8 -0
  75. package/dist/expressions/errors/get-line-start.d.ts +1 -0
  76. package/dist/expressions/errors/get-line-start.js +8 -0
  77. package/dist/expressions/errors/index.d.ts +7 -0
  78. package/dist/expressions/errors/index.js +6 -0
  79. package/dist/expressions/errors/offset-to-position.d.ts +2 -0
  80. package/dist/expressions/errors/offset-to-position.js +17 -0
  81. package/dist/expressions/errors/types.d.ts +10 -0
  82. package/dist/expressions/errors/types.js +1 -0
  83. package/dist/expressions/evaluator/evaluate-binary.d.ts +4 -0
  84. package/dist/expressions/evaluator/evaluate-binary.js +21 -0
  85. package/dist/expressions/evaluator/evaluate-unary.d.ts +2 -0
  86. package/dist/expressions/evaluator/evaluate-unary.js +10 -0
  87. package/dist/expressions/evaluator/evaluate.d.ts +15 -0
  88. package/dist/expressions/evaluator/evaluate.js +62 -0
  89. package/dist/expressions/index.d.ts +7 -0
  90. package/dist/expressions/index.js +5 -0
  91. package/dist/expressions/lexer/predicates/is-alpha-numeric.d.ts +1 -0
  92. package/dist/expressions/lexer/predicates/is-alpha-numeric.js +5 -0
  93. package/dist/expressions/lexer/predicates/is-alpha.d.ts +1 -0
  94. package/dist/expressions/lexer/predicates/is-alpha.js +3 -0
  95. package/dist/expressions/lexer/predicates/is-binary-digit.d.ts +1 -0
  96. package/dist/expressions/lexer/predicates/is-binary-digit.js +3 -0
  97. package/dist/expressions/lexer/predicates/is-digit.d.ts +1 -0
  98. package/dist/expressions/lexer/predicates/is-digit.js +3 -0
  99. package/dist/expressions/lexer/predicates/is-hex-digit.d.ts +1 -0
  100. package/dist/expressions/lexer/predicates/is-hex-digit.js +4 -0
  101. package/dist/expressions/lexer/predicates/is-octal-digit.d.ts +1 -0
  102. package/dist/expressions/lexer/predicates/is-octal-digit.js +3 -0
  103. package/dist/expressions/lexer/tokenize/consume-digits.d.ts +1 -0
  104. package/dist/expressions/lexer/tokenize/consume-digits.js +5 -0
  105. package/dist/expressions/lexer/tokenize/scan-identifier.d.ts +6 -0
  106. package/dist/expressions/lexer/tokenize/scan-identifier.js +20 -0
  107. package/dist/expressions/lexer/tokenize/scan-number.d.ts +4 -0
  108. package/dist/expressions/lexer/tokenize/scan-number.js +32 -0
  109. package/dist/expressions/lexer/tokenize/scan-operator.d.ts +6 -0
  110. package/dist/expressions/lexer/tokenize/scan-operator.js +71 -0
  111. package/dist/expressions/lexer/tokenize/scan-string-literal.d.ts +4 -0
  112. package/dist/expressions/lexer/tokenize/scan-string-literal.js +22 -0
  113. package/dist/expressions/lexer/tokenize/scan-string.d.ts +4 -0
  114. package/dist/expressions/lexer/tokenize/scan-string.js +98 -0
  115. package/dist/expressions/lexer/tokenize/scan-template-literal.d.ts +4 -0
  116. package/dist/expressions/lexer/tokenize/scan-template-literal.js +51 -0
  117. package/dist/expressions/lexer/tokenize/tokenize.d.ts +4 -0
  118. package/dist/expressions/lexer/tokenize/tokenize.js +99 -0
  119. package/dist/expressions/lexer/types.d.ts +12 -0
  120. package/dist/expressions/lexer/types.js +1 -0
  121. package/dist/expressions/parser/parse-array-literal.d.ts +3 -0
  122. package/dist/expressions/parser/parse-array-literal.js +15 -0
  123. package/dist/expressions/parser/parse-expression.d.ts +3 -0
  124. package/dist/expressions/parser/parse-expression.js +74 -0
  125. package/dist/expressions/parser/parse-object-literal.d.ts +3 -0
  126. package/dist/expressions/parser/parse-object-literal.js +69 -0
  127. package/dist/expressions/parser/parse-pipe-transform.d.ts +3 -0
  128. package/dist/expressions/parser/parse-pipe-transform.js +26 -0
  129. package/dist/expressions/parser/parse-postfix.d.ts +3 -0
  130. package/dist/expressions/parser/parse-postfix.js +23 -0
  131. package/dist/expressions/parser/parse-primary.d.ts +3 -0
  132. package/dist/expressions/parser/parse-primary.js +35 -0
  133. package/dist/expressions/parser/parse-template-literal.d.ts +3 -0
  134. package/dist/expressions/parser/parse-template-literal.js +41 -0
  135. package/dist/expressions/parser/parse-unary.d.ts +3 -0
  136. package/dist/expressions/parser/parse-unary.js +28 -0
  137. package/dist/expressions/parser/parse.d.ts +3 -0
  138. package/dist/expressions/parser/parse.js +26 -0
  139. package/dist/expressions/parser/parser-context.d.ts +12 -0
  140. package/dist/expressions/parser/parser-context.js +14 -0
  141. package/dist/expressions/parser/precedence.d.ts +1 -0
  142. package/dist/expressions/parser/precedence.js +8 -0
  143. package/dist/expressions/parser/types.d.ts +101 -0
  144. package/dist/expressions/parser/types.js +1 -0
  145. package/dist/expressions/plugin.d.ts +20 -0
  146. package/dist/expressions/plugin.js +1 -0
  147. package/dist/expressions/plugins/access.d.ts +2 -0
  148. package/dist/expressions/plugins/access.js +138 -0
  149. package/dist/expressions/plugins/arrows.d.ts +2 -0
  150. package/dist/expressions/plugins/arrows.js +83 -0
  151. package/dist/expressions/plugins/booleans.d.ts +2 -0
  152. package/dist/expressions/plugins/booleans.js +34 -0
  153. package/dist/expressions/plugins/collections.d.ts +2 -0
  154. package/dist/expressions/plugins/collections.js +70 -0
  155. package/dist/expressions/plugins/comparison.d.ts +2 -0
  156. package/dist/expressions/plugins/comparison.js +51 -0
  157. package/dist/expressions/plugins/date-identifier.d.ts +4 -0
  158. package/dist/expressions/plugins/date-identifier.js +29 -0
  159. package/dist/expressions/plugins/date-literal.d.ts +2 -0
  160. package/dist/expressions/plugins/date-literal.js +71 -0
  161. package/dist/expressions/plugins/logical.d.ts +2 -0
  162. package/dist/expressions/plugins/logical.js +103 -0
  163. package/dist/expressions/plugins/membership.d.ts +2 -0
  164. package/dist/expressions/plugins/membership.js +71 -0
  165. package/dist/expressions/plugins/pipe.d.ts +2 -0
  166. package/dist/expressions/plugins/pipe.js +57 -0
  167. package/dist/expressions/plugins/quoted-identifier.d.ts +2 -0
  168. package/dist/expressions/plugins/quoted-identifier.js +35 -0
  169. package/dist/expressions/plugins/resolved-identifier.d.ts +5 -0
  170. package/dist/expressions/plugins/resolved-identifier.js +19 -0
  171. package/dist/expressions/plugins/standard.d.ts +15 -0
  172. package/dist/expressions/plugins/standard.js +27 -0
  173. package/dist/expressions/plugins/strings.d.ts +2 -0
  174. package/dist/expressions/plugins/strings.js +44 -0
  175. package/dist/expressions/plugins/ternary.d.ts +2 -0
  176. package/dist/expressions/plugins/ternary.js +58 -0
  177. package/dist/expressions.d.ts +2 -0
  178. package/dist/expressions.js +2 -0
  179. package/dist/index.d.ts +1 -0
  180. package/package.json +12 -5
package/README.md CHANGED
@@ -35,7 +35,7 @@ to **LyteNyte Grid PRO** for advanced enterprise features and support.
35
35
  [![NPM Version](https://img.shields.io/npm/v/%401771technologies%2Flytenyte-core?label=Core&style=flat&logo=npm&logoColor=white)](https://www.npmjs.com/package/@1771technologies/lytenyte-core)
36
36
  [![GitHub branch status](https://img.shields.io/github/checks-status/1771-Technologies/lytenyte/main?style=flat&logo=github)](https://github.com/1771-Technologies/lytenyte/tree/main)
37
37
  [![GitHub Repo stars](https://img.shields.io/github/stars/1771-Technologies/lytenyte?style=flat&logo=github)](https://github.com/1771-Technologies/lytenyte)
38
- [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa?style=flat)](code_of_conduct.md)
38
+ [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa?style=flat)](https://github.com/1771-Technologies/lytenyte/blob/main/CODE_OF_CONDUCT.md)
39
39
  [![CI Status](https://img.shields.io/github/actions/workflow/status/1771-Technologies/lytenyte/release.yml?branch=main&style=flat&label=CI&logo=github)](https://github.com/1771-Technologies/lytenyte/actions/workflows/release.yml?query=branch%3Amain)
40
40
  [![Follow on X](https://img.shields.io/twitter/follow/1771tech?label=follow+1771tech&style=social&logo=x&logoColor=black)](https://x.com/1771tech)
41
41
  [![LinkedIn](https://img.shields.io/badge/LinkedIn-Follow-0A66C2?style=flat&logo=linkedin&logoColor=white)](https://www.linkedin.com/company/1771technologies)
@@ -55,14 +55,34 @@ to **LyteNyte Grid PRO** for advanced enterprise features and support.
55
55
 
56
56
  LyteNyte Grid is available in two editions:
57
57
 
58
- 1. **LyteNyte Grid Core: Free, open-source edition** for building high-performance data tables.
59
- Includes sorting, filtering, editing, row selection, detail views, and more. Also includes advanced
60
- features such as aggregation, row grouping, and data export, often locked behind paywalls in other grids.
58
+ 1. **LyteNyte Grid Core:** Free, **open-source edition** for building high-performance data tables. Includes sorting,
59
+ filtering, editing, row selection, detail views, and more. Also includes advanced features such
60
+ as aggregation, row grouping, and cell range selection, often locked behind paywalls in other grids.
61
61
 
62
- 2. **LyteNyte Grid PRO: Commercial edition** that extends Core with powerful enterprise
63
- features such as server-side data loading, pivoting, tree data, component managers,
64
- and advanced filtering. Build custom menus, popovers and dialogs,
65
- and workflow-driven UIs with ease.
62
+ 2. **LyteNyte Grid PRO: Commercial edition** that extends Core with powerful enterprise features,
63
+ including server-side data loading, pivoting, tree data, component managers, and advanced
64
+ filtering. Build custom menus, popovers, expressions, and workflow-driven UIs with ease.
65
+
66
+ ## AI-Enhanced Workflows
67
+
68
+ **LyteNyte Grid AI Skills** are structured context files for Claude Code, Windsurf, Cursor, and other AI coding agents.
69
+ Skills provide agents with accurate, curated context for LyteNyte Grid, allowing them to generate complex
70
+ grid implementations with greater speed and reliability.
71
+
72
+ Instead of building the grid manually, developers can describe the
73
+ desired result and let the agent generate the implementation.
74
+
75
+ **Install LyteNyte Grid AI Skills**
76
+
77
+ ```bash
78
+ npx skills add 1771-Technologies/lytenyte
79
+ ```
80
+
81
+ Once installed, the Skill activates automatically whenever you work on a LyteNyte Grid task. No
82
+ special prompting is needed. Skills are actively maintained by the 1771 Technologies
83
+ team and versioned alongside each LyteNyte Grid release.
84
+
85
+ See our [AI Skills Overview guide](https://1771technologies.com/docs/ai-skills-overview) to learn more.
66
86
 
67
87
  ## Features
68
88
 
@@ -79,6 +99,16 @@ LyteNyte Grid is available in two editions:
79
99
 
80
100
  </details>
81
101
 
102
+ <details>
103
+ <summary><b>🤖&nbsp; AI Enhanced Workflows</b></summary>
104
+ <br>
105
+
106
+ | Feature | Core | PRO |
107
+ | --------------------------------------------------------------------- | :--: | :-: |
108
+ | [AI Skills](https://www.1771technologies.com/docs/ai-skills-overview) | ✅ | ✅ |
109
+
110
+ </details>
111
+
82
112
  <details>
83
113
  <summary><b>🔌&nbsp; API Extensions</b></summary>
84
114
  <br>
@@ -198,8 +228,8 @@ LyteNyte Grid is available in two editions:
198
228
  | &nbsp;&nbsp;&nbsp;↳ [Checkbox Row Selection](https://www.1771technologies.com/docs/row-selection#checkbox-selection) | ✅ | ✅ |
199
229
  | &nbsp;&nbsp;&nbsp;↳ [Isolated Row Selection](https://www.1771technologies.com/docs/row-selection#isolated-row-selection) | ✅ | ✅ |
200
230
  | &nbsp;&nbsp;&nbsp;↳ [Linked Row Selection](https://www.1771technologies.com/docs/row-selection#linked-row-selection) | ✅ | ✅ |
201
- | [Cell Selection](https://www.1771technologies.com/docs/cell-selection#single-range-selection) | | ✅ |
202
- | [Cell Range Selection](https://www.1771technologies.com/docs/cell-selection#multi-range-selection) | | ✅ |
231
+ | [Cell Selection](https://www.1771technologies.com/docs/cell-selection#single-range-selection) | | ✅ |
232
+ | [Cell Range Selection](https://www.1771technologies.com/docs/cell-selection#multi-range-selection) | | ✅ |
203
233
 
204
234
  </details>
205
235
 
@@ -239,6 +269,19 @@ LyteNyte Grid is available in two editions:
239
269
 
240
270
  </details>
241
271
 
272
+ <details>
273
+ <summary><b>🧮&nbsp; Expressions</b> &nbsp;</summary>
274
+ <br>
275
+
276
+ | Feature | Core | PRO |
277
+ | -------------------------------------------------------------------------------- | :--: | :-: |
278
+ | [Expressions Engine](https://www.1771technologies.com/docs/expressions-overview) | — | ✅ |
279
+ | [Filter Expressions](https://www.1771technologies.com/docs/expression-filters) | — | ✅ |
280
+ | [Expression Editor](https://www.1771technologies.com/docs/expression-editor) | — | ✅ |
281
+ | [Expression Plugins](https://www.1771technologies.com/docs/expression-plugins) | — | ✅ |
282
+
283
+ </details>
284
+
242
285
  <details>
243
286
  <summary><b>📦&nbsp; Grouping & Aggregations</b></summary>
244
287
  <br>
@@ -377,7 +420,7 @@ npm install --save @1771technologies/lytenyte-pro
377
420
 
378
421
  > [!NOTE]
379
422
  > You can install and use LyteNyte Grid PRO
380
- > without license but a watermark will be displayed.
423
+ > without a license, but a watermark will be displayed.
381
424
 
382
425
  **Core:**
383
426
 
@@ -0,0 +1,106 @@
1
+ @layer ln-grid {
2
+ [data-ln-expression-editor] {
3
+ --ln-expr-number: light-dark(#b45309, #fab387);
4
+ --ln-expr-string: light-dark(#15803d, #a6e3a1);
5
+ --ln-expr-date: light-dark(#0e7490, #89dceb);
6
+ --ln-expr-keyword: light-dark(#7c3aed, #cba6f7);
7
+ --ln-expr-identifier: light-dark(#0369a1, #89b4fa);
8
+ --ln-expr-operator: light-dark(#be185d, #f38ba8);
9
+ --ln-expr-punctuation: light-dark(#6b7280, #6c7086);
10
+ --ln-expr-error: light-dark(#dc2626, #f38ba8);
11
+ }
12
+
13
+ /* These must be identical otherwise the highlight will not match the input. */
14
+ [data-ln-expression-editor] {
15
+ font-family:
16
+ ui-monospace, "Cascadia Code", "Segoe UI Mono", "Liberation Mono", Menlo, Monaco, Consolas, monospace;
17
+ font-size: var(--ln-font-sm);
18
+ white-space: nowrap;
19
+ word-break: normal;
20
+ overflow-wrap: normal;
21
+ tab-size: 2;
22
+ box-sizing: border-box;
23
+ }
24
+
25
+ [data-ln-expression-input] {
26
+ caret-color: var(--ln-text);
27
+ box-sizing: border-box;
28
+
29
+ transition-property: border-color;
30
+ transition-duration: var(--ln-transition-duration);
31
+ transition-timing-function: var(--ln-transition-fn);
32
+ }
33
+
34
+ /* Completion popover */
35
+ @keyframes ln-expr-popover-in {
36
+ from {
37
+ opacity: 0;
38
+ translate: 0 -4px;
39
+ }
40
+ to {
41
+ opacity: 1;
42
+ translate: 0 0;
43
+ }
44
+ }
45
+
46
+ [data-ln-expression-popover] {
47
+ background-color: var(--ln-bg-popover);
48
+ border: 1px solid var(--ln-border-popover);
49
+ border-radius: var(--ln-radius-md);
50
+ box-shadow: var(--ln-shadow-400);
51
+ padding: var(--ln-space-05);
52
+ min-width: 200px;
53
+ max-width: 360px;
54
+ box-sizing: border-box;
55
+ overflow: hidden;
56
+
57
+ &:popover-open {
58
+ animation: ln-expr-popover-in var(--ln-transition-duration) var(--ln-transition-fn) both;
59
+ }
60
+ }
61
+
62
+ [data-ln-expression-completion-list] {
63
+ list-style: none;
64
+ margin: 0;
65
+ padding: 0;
66
+ max-height: 220px;
67
+ overflow-y: auto;
68
+ overscroll-behavior: contain;
69
+
70
+ /* Thin scrollbar */
71
+ scrollbar-width: thin;
72
+ scrollbar-color: var(--ln-border-strong) transparent;
73
+ }
74
+
75
+ [data-ln-expression-completion-item] {
76
+ display: flex;
77
+ align-items: center;
78
+ gap: var(--ln-space-10);
79
+ padding-block: var(--ln-space-05);
80
+ padding-inline: var(--ln-space-10);
81
+ border-radius: var(--ln-radius);
82
+ font-family:
83
+ ui-monospace, "Cascadia Code", "Segoe UI Mono", "Liberation Mono", Menlo, Monaco, Consolas, monospace;
84
+ font-size: var(--ln-font-sm);
85
+ color: var(--ln-text);
86
+ cursor: pointer;
87
+ user-select: none;
88
+
89
+ transition-property: background-color, color;
90
+ transition-duration: var(--ln-transition-duration);
91
+ transition-timing-function: var(--ln-transition-fn);
92
+
93
+ &:hover {
94
+ background-color: var(--ln-bg-row-hover);
95
+ }
96
+
97
+ &[data-ln-selected] {
98
+ background-color: var(--ln-primary-10);
99
+ color: var(--ln-text-dark);
100
+
101
+ &:hover {
102
+ background-color: var(--ln-primary-10);
103
+ }
104
+ }
105
+ }
106
+ }
@@ -9,5 +9,10 @@ export interface ColumnManagerProps<Spec extends GridSpec = GridSpec> {
9
9
  columns: Column<Spec>[];
10
10
  row: RowNode<Spec["data"]>;
11
11
  }) => ReactNode;
12
+ /**
13
+ * @alpha
14
+ * Use with caution.
15
+ */
16
+ readonly getPillManagerTag?: (column: Column<Spec>) => Record<string, string>;
12
17
  }
13
- export declare function ColumnManager<Spec extends GridSpec = GridSpec>({ columns: provided, base, onColumnsChange, endElement, }: ColumnManagerProps<Spec>): import("react/jsx-runtime").JSX.Element;
18
+ export declare function ColumnManager<Spec extends GridSpec = GridSpec>({ columns: provided, base, onColumnsChange, endElement, getPillManagerTag, }: ColumnManagerProps<Spec>): import("react/jsx-runtime").JSX.Element;
@@ -3,7 +3,7 @@ import { useMemo } from "react";
3
3
  import { TreeView } from "../tree-view/index.js";
4
4
  import { Checkbox } from "../checkbox/checkbox.js";
5
5
  import { computePathMatrix } from "@1771technologies/lytenyte-shared";
6
- export function ColumnManager({ columns: provided, base, onColumnsChange, endElement, }) {
6
+ export function ColumnManager({ columns: provided, base, onColumnsChange, endElement, getPillManagerTag, }) {
7
7
  const nonAdjacentSplit = useMemo(() => {
8
8
  const paths = computePathMatrix(provided);
9
9
  const adjusted = [];
@@ -24,7 +24,28 @@ export function ColumnManager({ columns: provided, base, onColumnsChange, endEle
24
24
  const items = useMemo(() => {
25
25
  return nonAdjacentSplit.map((x) => ({ id: x.id, path: x.groupPath ?? [], name: x.name, column: x }));
26
26
  }, [nonAdjacentSplit]);
27
- return (_jsx(TreeView, { items: items, rowSelectionEnabled: false, draggable: true, rowHeight: 30, rowSelectAllShow: false, defaultExpansion: true, onItemsReordered: (x) => {
27
+ const getDragItems = useMemo(() => {
28
+ if (!getPillManagerTag)
29
+ return undefined;
30
+ return (row, leafs) => {
31
+ if (leafs.length || row.kind !== "leaf")
32
+ return {};
33
+ const column = row.data.column;
34
+ const mapTags = Object.entries(getPillManagerTag(column));
35
+ if (!mapTags.length)
36
+ return {};
37
+ return {
38
+ pill: {
39
+ kind: "site",
40
+ data: {
41
+ id: "__external__",
42
+ item: Object.fromEntries(mapTags),
43
+ },
44
+ },
45
+ };
46
+ };
47
+ }, [getPillManagerTag]);
48
+ return (_jsx(TreeView, { items: items, rowSelectionEnabled: false, draggable: true, rowHeight: 30, rowSelectAllShow: false, getDragTags: getDragItems, defaultExpansion: true, onItemsReordered: (x) => {
28
49
  const columns = x.map((x) => provided.find((p) => p.id === x.column.id));
29
50
  onColumnsChange(columns);
30
51
  }, children: ({ row, leafs, toggle, dragProps, isOver, isBefore }) => {
@@ -0,0 +1,10 @@
1
+ import type { Token } from "../../expressions/lexer/types.js";
2
+ import type { CompletionItem } from "./types.js";
3
+ export type ContextEntry = {
4
+ value: unknown;
5
+ type: "string" | "number" | "array" | "object" | "function" | "boolean" | "date";
6
+ return?: "string" | "number" | "array" | "object" | "date";
7
+ };
8
+ type CompletionContext = Record<string, ContextEntry>;
9
+ export declare function createCompletionProvider(context: CompletionContext): (tokens: Token[], cursorPosition: number) => CompletionItem[];
10
+ export {};
@@ -0,0 +1,391 @@
1
+ const STRING_METHODS = [
2
+ { label: "at", kind: "function" },
3
+ { label: "charAt", kind: "function" },
4
+ { label: "charCodeAt", kind: "function" },
5
+ { label: "endsWith", kind: "function" },
6
+ { label: "includes", kind: "function" },
7
+ { label: "indexOf", kind: "function" },
8
+ { label: "lastIndexOf", kind: "function" },
9
+ { label: "length", kind: "number" },
10
+ { label: "match", kind: "function" },
11
+ { label: "padEnd", kind: "function" },
12
+ { label: "padStart", kind: "function" },
13
+ { label: "repeat", kind: "function" },
14
+ { label: "replace", kind: "function" },
15
+ { label: "replaceAll", kind: "function" },
16
+ { label: "slice", kind: "function" },
17
+ { label: "split", kind: "function" },
18
+ { label: "startsWith", kind: "function" },
19
+ { label: "substring", kind: "function" },
20
+ { label: "toLowerCase", kind: "function" },
21
+ { label: "toUpperCase", kind: "function" },
22
+ { label: "trim", kind: "function" },
23
+ { label: "trimEnd", kind: "function" },
24
+ { label: "trimStart", kind: "function" },
25
+ ];
26
+ const ARRAY_METHODS = [
27
+ { label: "at", kind: "function" },
28
+ { label: "concat", kind: "function" },
29
+ { label: "entries", kind: "function" },
30
+ { label: "every", kind: "function" },
31
+ { label: "filter", kind: "function" },
32
+ { label: "find", kind: "function" },
33
+ { label: "findIndex", kind: "function" },
34
+ { label: "flat", kind: "function" },
35
+ { label: "flatMap", kind: "function" },
36
+ { label: "forEach", kind: "function" },
37
+ { label: "includes", kind: "function" },
38
+ { label: "indexOf", kind: "function" },
39
+ { label: "join", kind: "function" },
40
+ { label: "keys", kind: "function" },
41
+ { label: "length", kind: "number" },
42
+ { label: "map", kind: "function" },
43
+ { label: "reduce", kind: "function" },
44
+ { label: "reduceRight", kind: "function" },
45
+ { label: "reverse", kind: "function" },
46
+ { label: "slice", kind: "function" },
47
+ { label: "some", kind: "function" },
48
+ { label: "sort", kind: "function" },
49
+ { label: "values", kind: "function" },
50
+ ];
51
+ const DATE_METHODS = [
52
+ { label: "getTime", kind: "function" },
53
+ { label: "toISOString", kind: "function" },
54
+ ];
55
+ const NUMBER_METHODS = [
56
+ { label: "toExponential", kind: "function" },
57
+ { label: "toFixed", kind: "function" },
58
+ { label: "toLocaleString", kind: "function" },
59
+ { label: "toPrecision", kind: "function" },
60
+ { label: "toString", kind: "function" },
61
+ { label: "valueOf", kind: "function" },
62
+ ];
63
+ function isDot(token) {
64
+ return (token.type === "Punctuation" && token.value === ".") || token.type === "OptionalChain";
65
+ }
66
+ function isClosingBracket(token) {
67
+ return token.type === "Punctuation" && token.value === "]";
68
+ }
69
+ function isCompleteValue(token) {
70
+ return (token.type === "Identifier" ||
71
+ token.type === "QuotedIdentifier" ||
72
+ token.type === "Number" ||
73
+ token.type === "String" ||
74
+ token.type === "TemplateLiteral" ||
75
+ (token.type === "Punctuation" && (token.value === ")" || token.value === "]")));
76
+ }
77
+ function isStringLiteral(token) {
78
+ return token.type === "String" || token.type === "TemplateLiteral";
79
+ }
80
+ const BINARY_OPERATORS = [
81
+ { label: "+ Plus", kind: "operator", value: "+" },
82
+ { label: "- Minus", kind: "operator", value: "-" },
83
+ { label: "* Multiply", kind: "operator", value: "*" },
84
+ { label: "/ Divide", kind: "operator", value: "/" },
85
+ { label: "% Modulus", kind: "operator", value: "%" },
86
+ { label: "** Exponentiation", kind: "operator", value: "**" },
87
+ { label: "== Equal To", kind: "operator", value: "==" },
88
+ { label: "!= Not Equal To", kind: "operator", value: "!=" },
89
+ { label: "< Less Than", kind: "operator", value: "<" },
90
+ { label: "<= Less Than Or Equal To", kind: "operator", value: "<=" },
91
+ { label: "> Greater Than", kind: "operator", value: ">" },
92
+ { label: ">= Greater Than Or Equal To", kind: "operator", value: ">=" },
93
+ { label: "&& AND", kind: "operator", value: "&&" },
94
+ { label: "|| OR", kind: "operator", value: "||" },
95
+ { label: "?? OR if Null", kind: "operator", value: "??" },
96
+ { label: "|> Pipe", kind: "operator", value: "|>" },
97
+ ];
98
+ const STRING_METHOD_RETURNS = {
99
+ at: "string",
100
+ charAt: "string",
101
+ charCodeAt: "number",
102
+ endsWith: "unknown",
103
+ includes: "unknown",
104
+ indexOf: "number",
105
+ lastIndexOf: "number",
106
+ match: "array",
107
+ padEnd: "string",
108
+ padStart: "string",
109
+ repeat: "string",
110
+ replace: "string",
111
+ replaceAll: "string",
112
+ slice: "string",
113
+ split: "array",
114
+ startsWith: "unknown",
115
+ substring: "string",
116
+ toLowerCase: "string",
117
+ toUpperCase: "string",
118
+ trim: "string",
119
+ trimEnd: "string",
120
+ trimStart: "string",
121
+ };
122
+ const ARRAY_METHOD_RETURNS = {
123
+ at: "unknown",
124
+ concat: "array",
125
+ entries: "unknown",
126
+ every: "unknown",
127
+ filter: "array",
128
+ find: "unknown",
129
+ findIndex: "number",
130
+ flat: "array",
131
+ flatMap: "array",
132
+ forEach: "unknown",
133
+ includes: "unknown",
134
+ indexOf: "number",
135
+ join: "string",
136
+ keys: "unknown",
137
+ map: "array",
138
+ reduce: "unknown",
139
+ reduceRight: "unknown",
140
+ reverse: "array",
141
+ slice: "array",
142
+ some: "unknown",
143
+ sort: "array",
144
+ values: "unknown",
145
+ };
146
+ const DATE_METHOD_RETURNS = {
147
+ getTime: "number",
148
+ toISOString: "string",
149
+ };
150
+ function kindOf(value) {
151
+ if (typeof value === "function")
152
+ return "function";
153
+ if (Array.isArray(value))
154
+ return "array";
155
+ if (typeof value === "string")
156
+ return "string";
157
+ if (typeof value === "number")
158
+ return "number";
159
+ if (typeof value === "boolean")
160
+ return "boolean";
161
+ if (typeof value === "object" && value !== null)
162
+ return "object";
163
+ return "unknown";
164
+ }
165
+ function isContextEntry(v) {
166
+ return v != null && typeof v === "object" && "type" in v && "value" in v;
167
+ }
168
+ function resolveEntry(context, path) {
169
+ if (path.length === 0)
170
+ return undefined;
171
+ let entry = context[path[0]];
172
+ for (let i = 1; i < path.length; i++) {
173
+ if (!entry || entry.value == null || typeof entry.value !== "object")
174
+ return undefined;
175
+ const nested = entry.value[path[i]];
176
+ if (isContextEntry(nested)) {
177
+ entry = nested;
178
+ }
179
+ else if (nested !== undefined) {
180
+ entry = { value: nested, type: kindOf(nested) };
181
+ }
182
+ else {
183
+ return undefined;
184
+ }
185
+ }
186
+ return entry;
187
+ }
188
+ function findMatchingOpenParen(relevant, closeIndex) {
189
+ let depth = 1;
190
+ let i = closeIndex - 1;
191
+ while (i >= 0) {
192
+ if (relevant[i].type === "Punctuation") {
193
+ if (relevant[i].value === ")")
194
+ depth++;
195
+ else if (relevant[i].value === "(") {
196
+ if (--depth === 0)
197
+ return i;
198
+ }
199
+ }
200
+ i--;
201
+ }
202
+ return -1;
203
+ }
204
+ function buildPathFromTokens(relevant, i) {
205
+ const tokenName = (t) => (t.type === "QuotedIdentifier" ? t.value.slice(2, -1) : t.value);
206
+ const token = relevant[i];
207
+ if (!token || (token.type !== "Identifier" && token.type !== "QuotedIdentifier"))
208
+ return null;
209
+ const path = [tokenName(token)];
210
+ let j = i - 1;
211
+ while (j >= 1 && isDot(relevant[j])) {
212
+ j--;
213
+ if (relevant[j].type !== "Identifier" && relevant[j].type !== "QuotedIdentifier")
214
+ break;
215
+ path.unshift(tokenName(relevant[j]));
216
+ j--;
217
+ }
218
+ return path;
219
+ }
220
+ function resolveTypeOf(relevant, i, context) {
221
+ const token = relevant[i];
222
+ if (!token)
223
+ return "unknown";
224
+ if (token.type === "DateLiteral")
225
+ return "date";
226
+ if (isStringLiteral(token))
227
+ return "string";
228
+ if (isClosingBracket(token))
229
+ return "array";
230
+ if (token.type === "Punctuation" && token.value === ")") {
231
+ const openIdx = findMatchingOpenParen(relevant, i);
232
+ if (openIdx < 1)
233
+ return "unknown";
234
+ const methodToken = relevant[openIdx - 1];
235
+ if (methodToken?.type !== "Identifier")
236
+ return "unknown";
237
+ const hasDot = openIdx >= 2 && isDot(relevant[openIdx - 2]);
238
+ if (!hasDot) {
239
+ // Top-level function call: fn(...)
240
+ const funcEntry = context[methodToken.value];
241
+ if (funcEntry?.type === "function" && funcEntry.return)
242
+ return funcEntry.return;
243
+ return "unknown";
244
+ }
245
+ // Method call: receiver.method(...)
246
+ // First try resolving the receiver as a context object to find a typed method entry
247
+ const receiverPath = buildPathFromTokens(relevant, openIdx - 3);
248
+ if (receiverPath) {
249
+ const receiverEntry = resolveEntry(context, receiverPath);
250
+ if (receiverEntry?.type === "object" && receiverEntry.value != null) {
251
+ const methodVal = receiverEntry.value[methodToken.value];
252
+ const methodEntry = isContextEntry(methodVal) ? methodVal : undefined;
253
+ if (methodEntry?.type === "function" && methodEntry.return)
254
+ return methodEntry.return;
255
+ }
256
+ }
257
+ // Fall back to builtin method return-type maps (string/array prototype methods)
258
+ const receiverType = resolveTypeOf(relevant, openIdx - 3, context);
259
+ if (receiverType === "string")
260
+ return STRING_METHOD_RETURNS[methodToken.value] ?? "unknown";
261
+ if (receiverType === "array")
262
+ return ARRAY_METHOD_RETURNS[methodToken.value] ?? "unknown";
263
+ if (receiverType === "date")
264
+ return DATE_METHOD_RETURNS[methodToken.value] ?? "unknown";
265
+ return "unknown";
266
+ }
267
+ if (token.type === "Identifier" || token.type === "QuotedIdentifier") {
268
+ const path = buildPathFromTokens(relevant, i);
269
+ if (!path)
270
+ return "unknown";
271
+ const entry = resolveEntry(context, path);
272
+ const kind = entry?.type ?? "unknown";
273
+ if (kind === "string" || kind === "number" || kind === "array" || kind === "object")
274
+ return kind;
275
+ return "unknown";
276
+ }
277
+ return "unknown";
278
+ }
279
+ function analyzeTokens(tokens, cursorPosition, context) {
280
+ const relevant = tokens.filter((t) => t.end <= cursorPosition && t.type !== "EOF" && t.type !== "Whitespace");
281
+ if (relevant.length === 0)
282
+ return { kind: "top-level" };
283
+ let i = relevant.length - 1;
284
+ // Skip the partial word the user is currently typing (only if cursor is at its end)
285
+ if (relevant[i].type === "Identifier" && relevant[i].end === cursorPosition)
286
+ i--;
287
+ if (i < 0)
288
+ return { kind: "top-level" };
289
+ // If the token before the word isn't a dot, check if it's a complete value
290
+ if (!isDot(relevant[i])) {
291
+ if (isCompleteValue(relevant[i]))
292
+ return { kind: "after-value" };
293
+ return { kind: "top-level" };
294
+ }
295
+ // Step over the dot
296
+ i--;
297
+ if (i < 0)
298
+ return { kind: "none" };
299
+ const beforeDot = relevant[i];
300
+ // "hello". or `hello`. → string methods
301
+ if (isStringLiteral(beforeDot))
302
+ return { kind: "string-literal" };
303
+ // [1,2,3]. → array methods
304
+ if (isClosingBracket(beforeDot))
305
+ return { kind: "array-literal" };
306
+ // d"2023-02-11". → date methods
307
+ if (beforeDot.type === "DateLiteral")
308
+ return { kind: "date-value" };
309
+ // fn(). → resolve call return type recursively
310
+ if (beforeDot.type === "Punctuation" && beforeDot.value === ")") {
311
+ const resultType = resolveTypeOf(relevant, i, context);
312
+ if (resultType === "string")
313
+ return { kind: "string-literal" };
314
+ if (resultType === "number")
315
+ return { kind: "number-value" };
316
+ if (resultType === "array")
317
+ return { kind: "array-literal" };
318
+ if (resultType === "date")
319
+ return { kind: "date-value" };
320
+ return { kind: "none" };
321
+ }
322
+ // identifier chain: walk back through alternating Identifier / QuotedIdentifier / dot tokens
323
+ if (beforeDot.type === "Identifier" || beforeDot.type === "QuotedIdentifier") {
324
+ const tokenName = (t) => (t.type === "QuotedIdentifier" ? t.value.slice(2, -1) : t.value);
325
+ const path = [tokenName(beforeDot)];
326
+ i--;
327
+ while (i >= 1) {
328
+ if (!isDot(relevant[i]))
329
+ break;
330
+ i--;
331
+ if (relevant[i].type !== "Identifier" && relevant[i].type !== "QuotedIdentifier")
332
+ break;
333
+ path.unshift(tokenName(relevant[i]));
334
+ i--;
335
+ }
336
+ return { kind: "context-path", path };
337
+ }
338
+ return { kind: "none" };
339
+ }
340
+ const VALID_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
341
+ function objectCompletions(obj) {
342
+ return Object.entries(obj).map(([key, val]) => ({
343
+ label: key,
344
+ kind: isContextEntry(val) ? val.type : kindOf(val),
345
+ id: key,
346
+ value: VALID_IDENTIFIER.test(key) ? undefined : `@"${key}"`,
347
+ }));
348
+ }
349
+ function builtinCompletions(methods) {
350
+ return methods.map((m) => ({ label: m.label, kind: m.kind, id: m.label, value: m.value }));
351
+ }
352
+ function binaryOperatorCompletions() {
353
+ return builtinCompletions(BINARY_OPERATORS);
354
+ }
355
+ export function createCompletionProvider(context) {
356
+ return function completionProvider(tokens, cursorPosition) {
357
+ const analysis = analyzeTokens(tokens, cursorPosition, context);
358
+ switch (analysis.kind) {
359
+ case "top-level":
360
+ return objectCompletions(context);
361
+ case "string-literal":
362
+ return builtinCompletions(STRING_METHODS);
363
+ case "number-value":
364
+ return builtinCompletions(NUMBER_METHODS);
365
+ case "date-value":
366
+ return builtinCompletions(DATE_METHODS);
367
+ case "array-literal":
368
+ return builtinCompletions(ARRAY_METHODS);
369
+ case "context-path": {
370
+ const entry = resolveEntry(context, analysis.path);
371
+ if (!entry)
372
+ return [];
373
+ if (entry.type === "string")
374
+ return builtinCompletions(STRING_METHODS);
375
+ if (entry.type === "number")
376
+ return builtinCompletions(NUMBER_METHODS);
377
+ if (entry.type === "array")
378
+ return builtinCompletions(ARRAY_METHODS);
379
+ if (entry.type === "date")
380
+ return builtinCompletions(DATE_METHODS);
381
+ if (entry.type === "object" && entry.value != null && typeof entry.value === "object")
382
+ return objectCompletions(entry.value);
383
+ return [];
384
+ }
385
+ case "after-value":
386
+ return binaryOperatorCompletions();
387
+ case "none":
388
+ return [];
389
+ }
390
+ };
391
+ }