@spectric/ui 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitlab-ci.yml +28 -0
- package/.nvmrc +1 -0
- package/.storybook/analyze.sh +4 -0
- package/.storybook/main.ts +55 -0
- package/.storybook/preview.ts +42 -0
- package/.vscode/extensions.json +5 -0
- package/.vscode/settings.json +41 -0
- package/README.MD +50 -0
- package/html-include.png +0 -0
- package/package.json +33 -0
- package/src/classes/BitArray.ts +48 -0
- package/src/classes/DisposibleElement.ts +108 -0
- package/src/components/Banner.ts +102 -0
- package/src/components/Bitdisplay.ts +383 -0
- package/src/components/Button.ts +121 -0
- package/src/components/Header.ts +125 -0
- package/src/components/Page.ts +157 -0
- package/src/components/Panel.ts +56 -0
- package/src/components/ThemeProvider.ts +251 -0
- package/src/components/button.css.ts +160 -0
- package/src/components/configurations/classifications.ts +194 -0
- package/src/components/dialog/dialog.css.ts +50 -0
- package/src/components/dialog/dialog.ts +163 -0
- package/src/components/dialog/index.ts +1 -0
- package/src/components/header.css.ts +38 -0
- package/src/components/index.ts +10 -0
- package/src/components/input.css +75 -0
- package/src/components/input.ts +312 -0
- package/src/components/page.css.ts +158 -0
- package/src/components/panel.css.ts +44 -0
- package/src/components/query_bar/QueryBar.css +48 -0
- package/src/components/query_bar/QueryBar.ts +378 -0
- package/src/components/query_bar/index.ts +2 -0
- package/src/components/query_bar/querylanguage/kuery/ast/_generated_/kuery.js +3186 -0
- package/src/components/query_bar/querylanguage/kuery/ast/ast.ts +113 -0
- package/src/components/query_bar/querylanguage/kuery/ast/index.ts +31 -0
- package/src/components/query_bar/querylanguage/kuery/ast/kuery.peg +417 -0
- package/src/components/query_bar/querylanguage/kuery/functions/and.ts +55 -0
- package/src/components/query_bar/querylanguage/kuery/functions/exists.ts +62 -0
- package/src/components/query_bar/querylanguage/kuery/functions/index.ts +47 -0
- package/src/components/query_bar/querylanguage/kuery/functions/is.ts +211 -0
- package/src/components/query_bar/querylanguage/kuery/functions/nested.ts +63 -0
- package/src/components/query_bar/querylanguage/kuery/functions/not.ts +53 -0
- package/src/components/query_bar/querylanguage/kuery/functions/or.ts +56 -0
- package/src/components/query_bar/querylanguage/kuery/functions/range.ts +163 -0
- package/src/components/query_bar/querylanguage/kuery/functions/utils/get_fields.ts +49 -0
- package/src/components/query_bar/querylanguage/kuery/functions/utils/get_full_field_name_node.ts +87 -0
- package/src/components/query_bar/querylanguage/kuery/index.ts +38 -0
- package/src/components/query_bar/querylanguage/kuery/kuery_syntax_error.ts +76 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/function.ts +75 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/index.ts +46 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/literal.ts +42 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/named_arg.ts +47 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/types.ts +108 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/wildcard.ts +80 -0
- package/src/components/query_bar/querylanguage/kuery/types.ts +52 -0
- package/src/components/query_bar/querylanguage/outputTypes/toCQL.ts +122 -0
- package/src/components/query_bar/querylanguage/outputTypes/toMongo.ts +103 -0
- package/src/components/query_bar/querylanguage/utils.ts +35 -0
- package/src/components/query_bar/types.ts +59 -0
- package/src/components/splitview/index.ts +1 -0
- package/src/components/splitview/splitview.css.ts +66 -0
- package/src/components/splitview/splitview.ts +183 -0
- package/src/components/types.ts +35 -0
- package/src/index.ts +1 -0
- package/src/stories/Banner.stories.ts +46 -0
- package/src/stories/BitDisplay.stories.ts +68 -0
- package/src/stories/Button.stories.ts +138 -0
- package/src/stories/Header.stories.ts +55 -0
- package/src/stories/Page.stories.ts +108 -0
- package/src/stories/QueryBar.stories.ts +63 -0
- package/src/stories/Splitview.stories.ts +52 -0
- package/src/stories/fixtures/Bits.ts +15 -0
- package/src/stories/fixtures/ExampleContent.ts +102 -0
- package/src/stories/fixtures/data.ts +30 -0
- package/src/stories/fixtures/lorumipsum.ts +19 -0
- package/src/stories/input.stories.ts +77 -0
- package/src/stories/tsconfig.json +35 -0
- package/src/utils/debounce.ts +18 -0
- package/src/utils/spread.ts +71 -0
- package/src/vite-env.d.ts +1 -0
- package/test/__init__.py +9 -0
- package/test/elastic.py +9 -0
- package/test/interface.py +16 -0
- package/tsconfig.json +29 -0
- package/vite.config.js +34 -0
- package/vue-example.png +0 -0
- package/vue-include.png +0 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { html, LitElement, PropertyValues } from "lit";
|
|
2
|
+
import * as kuery from "./querylanguage/kuery"
|
|
3
|
+
import { customElement, property, query, queryAsync, state } from "lit/decorators.js";
|
|
4
|
+
import { SpectricInput } from "../input";
|
|
5
|
+
import { JsonObject } from "./types";
|
|
6
|
+
import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from "../types";
|
|
7
|
+
import "./QueryBar.css"
|
|
8
|
+
import { DialogElement } from "../dialog";
|
|
9
|
+
import { createRef, ref } from "lit/directives/ref.js";
|
|
10
|
+
import { SpectricButton } from "../Button";
|
|
11
|
+
export type FieldTypes = {
|
|
12
|
+
name: string;
|
|
13
|
+
type: "string" | "number" | "boolean"
|
|
14
|
+
format?: "date-time"
|
|
15
|
+
}
|
|
16
|
+
type SuggestionType = 'conjunction' | "field" | 'operator' | 'value'
|
|
17
|
+
type Suggestion = {
|
|
18
|
+
fieldName: string
|
|
19
|
+
end: number
|
|
20
|
+
prefix: string
|
|
21
|
+
start: number
|
|
22
|
+
suffix: string
|
|
23
|
+
suggestionTypes: (SuggestionType)[]
|
|
24
|
+
text: string
|
|
25
|
+
type: "cursor"
|
|
26
|
+
}
|
|
27
|
+
export enum SupportedLanguages {
|
|
28
|
+
MONGO = "toMongo",
|
|
29
|
+
CQL = "toCql",
|
|
30
|
+
DSL = "toDSL",
|
|
31
|
+
AST = "AST"
|
|
32
|
+
}
|
|
33
|
+
type SupportedLanguagesTypes = `${SupportedLanguages}`
|
|
34
|
+
interface QueryEventMap {
|
|
35
|
+
"change": (event: CustomEvent<string | kuery.KueryNode | JsonObject>) => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface IQueryProps {
|
|
39
|
+
/**
|
|
40
|
+
* The output of the query in a specific format
|
|
41
|
+
*/
|
|
42
|
+
outputLanguage: SupportedLanguagesTypes;
|
|
43
|
+
/**
|
|
44
|
+
* The output of the query
|
|
45
|
+
*/
|
|
46
|
+
value: string;
|
|
47
|
+
/**
|
|
48
|
+
* Fields that are used for the auto complete
|
|
49
|
+
*/
|
|
50
|
+
fields: FieldTypes[];
|
|
51
|
+
/**
|
|
52
|
+
* Callback that will provide values for specific fields
|
|
53
|
+
*/
|
|
54
|
+
getValuesForField: (field: string, text: string) => Promise<string[]>;
|
|
55
|
+
}
|
|
56
|
+
type LabelValue = {
|
|
57
|
+
label?: string;
|
|
58
|
+
value: string;
|
|
59
|
+
}
|
|
60
|
+
type Completion = LabelValue & {
|
|
61
|
+
start: number;
|
|
62
|
+
end: number;
|
|
63
|
+
type: SuggestionType
|
|
64
|
+
onSelect?: () => Promise<string | undefined | number>
|
|
65
|
+
}
|
|
66
|
+
const NumberOperators: Record<string, LabelValue> = {
|
|
67
|
+
"eq": { value: " : ", label: " equals some value" },
|
|
68
|
+
"gt": { value: " > ", label: " is greater than some value" },
|
|
69
|
+
"lt": { value: " < ", label: " is less than some value" },
|
|
70
|
+
"gte": { value: " >= ", label: " is greater than or equal to some value" },
|
|
71
|
+
"lte": { value: " <= ", label: " is less than or equal to some value" }
|
|
72
|
+
}
|
|
73
|
+
const StringOperators: Record<string, LabelValue> = {
|
|
74
|
+
"eq": { value: ": ", label: " equals some value" },
|
|
75
|
+
"exists": { value: ": *", label: " exists in any form" }
|
|
76
|
+
}
|
|
77
|
+
const BoolOperators: LabelValue[] = [{ value: ": true", label: " value is true" },
|
|
78
|
+
{ value: ": false", label: "value is false" }
|
|
79
|
+
]
|
|
80
|
+
//Date operators are the same as number but we want a string value
|
|
81
|
+
const DateOperators: Record<string, LabelValue> = Object.fromEntries(Object.entries(NumberOperators).map(([key, labelValue]) => [key, { value: labelValue.value, label: (labelValue.label || "").replace("value", "date-time") }]))
|
|
82
|
+
/**
|
|
83
|
+
* The Query component will take Opensearch Dashboard Query language and transform it into various outputs
|
|
84
|
+
*/
|
|
85
|
+
@customElement('spectric-query')
|
|
86
|
+
export class SpectricQuery extends LitElement implements IQueryProps {
|
|
87
|
+
private uuid: string;
|
|
88
|
+
constructor() {
|
|
89
|
+
super()
|
|
90
|
+
this.uuid = crypto.randomUUID()
|
|
91
|
+
}
|
|
92
|
+
protected createRenderRoot(): HTMLElement | DocumentFragment {
|
|
93
|
+
return this
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* The internal value.
|
|
98
|
+
*/
|
|
99
|
+
protected _value: string = '';
|
|
100
|
+
private suggestion?: Suggestion;
|
|
101
|
+
/**
|
|
102
|
+
* The value of the input.
|
|
103
|
+
*/
|
|
104
|
+
@property({ type: String, reflect: true })
|
|
105
|
+
get value() {
|
|
106
|
+
//pull directly from the input
|
|
107
|
+
if (this._input) {
|
|
108
|
+
return String(this._input.value)
|
|
109
|
+
}
|
|
110
|
+
// but before then _value will work fine
|
|
111
|
+
return this._value;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
set value(value) {
|
|
115
|
+
const oldValue = this._value;
|
|
116
|
+
this._value = value;
|
|
117
|
+
this.requestUpdate('value', oldValue);
|
|
118
|
+
// we set the value directly on the input (when available)
|
|
119
|
+
// so that programatic manipulation updates the UI correctly
|
|
120
|
+
if (this._input) {
|
|
121
|
+
this._input.value = String(value);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
@property({ type: String, reflect: true })
|
|
125
|
+
outputLanguage: SupportedLanguagesTypes = "AST";
|
|
126
|
+
@state()
|
|
127
|
+
private completions: Completion[] = [];
|
|
128
|
+
@state()
|
|
129
|
+
private completionIndex = 0;
|
|
130
|
+
@property({ type: Array, reflect: true })
|
|
131
|
+
fields: FieldTypes[] = [];
|
|
132
|
+
|
|
133
|
+
@query(".autocomplete")
|
|
134
|
+
_autocomplete?: HTMLDivElement
|
|
135
|
+
|
|
136
|
+
@queryAsync(".autocomplete")
|
|
137
|
+
//@ts-expect-error
|
|
138
|
+
_asyncAutocomplete: Promise<HTMLDivElement>
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The underlying input element
|
|
142
|
+
*/
|
|
143
|
+
@query('spectric-input')
|
|
144
|
+
protected _input!: SpectricInput;
|
|
145
|
+
_parseQuery = (e: InputEvent | undefined = undefined) => {
|
|
146
|
+
let ast;
|
|
147
|
+
if (this.value == "") {
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
if (e && e.data == "(") {
|
|
152
|
+
//Auto close parentheses or parsing and suggestions fail
|
|
153
|
+
this.value = this.value + " )"
|
|
154
|
+
this._input.setSelectionRange(this.value.length - 2, this.value.length - 2)
|
|
155
|
+
}
|
|
156
|
+
let value = this.value;
|
|
157
|
+
if (this._input.selectionStart !== null) {
|
|
158
|
+
value = value.substring(0, this._input.selectionStart) + "@kuery-cursor@" + value.substring(this._input.selectionStart)
|
|
159
|
+
}
|
|
160
|
+
//FIXME: make auto complete work well.
|
|
161
|
+
let suggestions = kuery.parse(value, { parseCursor: true, cursorSymbol: "@kuery-cursor@", allowLeadingWildcards: false }) as unknown as Suggestion;
|
|
162
|
+
this.autoComplete(suggestions)
|
|
163
|
+
|
|
164
|
+
ast = kuery.parse(this.value, { allowLeadingWildcards: false });
|
|
165
|
+
} catch (e: any) {
|
|
166
|
+
// this.completions = []
|
|
167
|
+
// this._input.invalid = true;
|
|
168
|
+
// let [expect, _, arrow] = e.message.split("\n")
|
|
169
|
+
// this._input.invalidText = html`  ${arrow} ${expect}`;
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
let output
|
|
173
|
+
if (this.outputLanguage == "AST") {
|
|
174
|
+
output = ast
|
|
175
|
+
} else {
|
|
176
|
+
output = kuery[this.outputLanguage](ast, this.fields)
|
|
177
|
+
}
|
|
178
|
+
let event = new CustomEvent("change", { detail: output })
|
|
179
|
+
this.dispatchEvent(event)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
getValuesForField = async (field: string, text: string): Promise<string[]> => {
|
|
183
|
+
console.log("getValuesForField isn't set no values returned", field, text)
|
|
184
|
+
return []
|
|
185
|
+
}
|
|
186
|
+
async autoComplete(suggestion: Suggestion) {
|
|
187
|
+
this.completions = []
|
|
188
|
+
if (suggestion.type !== "cursor") {
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
let completions = []
|
|
192
|
+
this.suggestion = suggestion
|
|
193
|
+
let { start, end } = suggestion
|
|
194
|
+
for (let type of suggestion.suggestionTypes) {
|
|
195
|
+
if (type == "conjunction" && suggestion.text.endsWith(' ')) {
|
|
196
|
+
completions.push(...["and ", "or "].map(value => ({ type, value, start: end, end: end })))
|
|
197
|
+
}
|
|
198
|
+
if (type === "field") {
|
|
199
|
+
let fieldCompletions = this.fields.filter(field => field.name.includes(suggestion.fieldName) || field.name.includes(suggestion.prefix)).map(f => {
|
|
200
|
+
return [{ type, value: f.name, start, end }]
|
|
201
|
+
}).flat()
|
|
202
|
+
completions.push(...fieldCompletions)
|
|
203
|
+
}
|
|
204
|
+
if (type === "operator") {
|
|
205
|
+
let fieldType = this.fields.find(field => field.name === suggestion.fieldName);
|
|
206
|
+
if (fieldType) {
|
|
207
|
+
if (fieldType.type === "number") {
|
|
208
|
+
completions.push(...Object.values(NumberOperators).map(value => ({ type, ...value, start: end, end: end })))
|
|
209
|
+
} else if (fieldType.type === "string") {
|
|
210
|
+
if (fieldType.format === "date-time") {
|
|
211
|
+
completions.push(...Object.values(DateOperators).map(value => ({
|
|
212
|
+
type, ...value, start: end, end: end, onSelect: async () => {
|
|
213
|
+
let values = await this.getValuesForField(suggestion.fieldName, suggestion.prefix);
|
|
214
|
+
if (values.length === 0) {
|
|
215
|
+
values = ["now-1m", "now-1d", "now-1M",]
|
|
216
|
+
}
|
|
217
|
+
let value: string | undefined;
|
|
218
|
+
let buttonRef = createRef<SpectricButton>()
|
|
219
|
+
await new Promise((resolve) => {
|
|
220
|
+
let dialog = DialogElement.display({}, html`
|
|
221
|
+
<div class="query-bar-date-quick-select">
|
|
222
|
+
${values.map(v => html`<a href="#" @click=${(e: MouseEvent) => {
|
|
223
|
+
e.preventDefault()
|
|
224
|
+
value = `"${v}"`;
|
|
225
|
+
resolve(value); dialog.open = false
|
|
226
|
+
}}>${v}</a>`)}
|
|
227
|
+
</div>
|
|
228
|
+
<spectric-input variant="datetime-local" @change=${(e: any) => {
|
|
229
|
+
if (!e.target) {
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
let date = (new Date(e.target.value + ":00.000Z")).toISOString()
|
|
233
|
+
value = `"${date}"`
|
|
234
|
+
buttonRef.value!.disabled = value === undefined
|
|
235
|
+
}}></spectric-input>
|
|
236
|
+
<spectric-button ${ref(buttonRef)} .disabled=${true} @click=${() => { resolve(value); dialog.open = false }}>Submit</spectric-button>
|
|
237
|
+
`)
|
|
238
|
+
})
|
|
239
|
+
return value
|
|
240
|
+
}
|
|
241
|
+
})))
|
|
242
|
+
} else {
|
|
243
|
+
completions.push(...Object.values(StringOperators).map(value => ({ type, ...value, start: end, end: end })))
|
|
244
|
+
}
|
|
245
|
+
} else if (fieldType.type === "boolean") {
|
|
246
|
+
completions.push(...BoolOperators.map(value => ({ type, ...value, start: end, end: end })))
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (type === "value") {
|
|
251
|
+
let fieldType = this.fields.find(field => field.name === suggestion.fieldName);
|
|
252
|
+
if (fieldType && fieldType.type == "boolean") {
|
|
253
|
+
completions.push({ type, value: "true", start, end }, { type, value: "false", start, end })
|
|
254
|
+
} else {
|
|
255
|
+
console.log(`invoke callback to get values for ${suggestion.fieldName}`)
|
|
256
|
+
let values = await this.getValuesForField(suggestion.fieldName, suggestion.prefix);
|
|
257
|
+
if (fieldType?.type === "string") {
|
|
258
|
+
//quote the values
|
|
259
|
+
values = values.map(v => `"${v}"`)
|
|
260
|
+
}
|
|
261
|
+
completions.push(...values.map(value => ({ type, value, start, end })))
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
this.completions = completions
|
|
267
|
+
if (this.completions.length && this._autocomplete) {
|
|
268
|
+
let { width } = this._input.getBoundingClientRect();
|
|
269
|
+
this._autocomplete.showPopover();
|
|
270
|
+
this._autocomplete.style.width = `${width - 15}px`;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
protected updated(changed: PropertyValues): void {
|
|
274
|
+
if (changed.has("outputLanguage")) {
|
|
275
|
+
this._parseQuery()
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
_selectCompletion = async () => {
|
|
279
|
+
if (!this.suggestion) {
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
let completion = this.completions[this.completionIndex]
|
|
283
|
+
|
|
284
|
+
let prefix = this.value.substring(0, completion.start) +
|
|
285
|
+
completion.value
|
|
286
|
+
let insertIndex = prefix.length
|
|
287
|
+
let afterStart = this.value.substring(completion.end)
|
|
288
|
+
if (completion.value.includes(afterStart)) {
|
|
289
|
+
this.value = prefix
|
|
290
|
+
} else {
|
|
291
|
+
this.value = prefix + this.value.substring(completion.end)
|
|
292
|
+
}
|
|
293
|
+
this._input.setSelectionRange(insertIndex, insertIndex)
|
|
294
|
+
if (completion.onSelect) {
|
|
295
|
+
let value = await completion.onSelect()
|
|
296
|
+
if (value !== undefined) {
|
|
297
|
+
this.value += value
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
this.completionIndex = 0;
|
|
301
|
+
this.completions = []
|
|
302
|
+
this._parseQuery()
|
|
303
|
+
}
|
|
304
|
+
_handleArrows = (e: KeyboardEvent) => {
|
|
305
|
+
if (e.key === "Escape") {
|
|
306
|
+
this.completions = []; //Escape closes the popover toplayer lets ensure the completions aren't selectable
|
|
307
|
+
}
|
|
308
|
+
if (e.key == "ArrowLeft" || e.key === "ArrowRight") {
|
|
309
|
+
setTimeout(this._parseQuery, 100)
|
|
310
|
+
}
|
|
311
|
+
if (!this.completions.length) {
|
|
312
|
+
return
|
|
313
|
+
}
|
|
314
|
+
if (["ArrowUp", "ArrowDown", 'Enter', "Tab"].includes(e.key) && this.suggestion) {
|
|
315
|
+
e.preventDefault();
|
|
316
|
+
if (e.key === "ArrowDown" || e.key === "Tab") {
|
|
317
|
+
this.completionIndex += 1;
|
|
318
|
+
if (this.completionIndex > this.completions.length - 1) {
|
|
319
|
+
this.completionIndex = 0
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (e.key === "ArrowUp") {
|
|
323
|
+
this.completionIndex -= 1;
|
|
324
|
+
if (this.completionIndex < 0) {
|
|
325
|
+
this.completionIndex = this.completions.length - 1
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
this._asyncAutocomplete?.then(element => {
|
|
330
|
+
let active = element.querySelector(".option.active");
|
|
331
|
+
if (active) {
|
|
332
|
+
active.scrollIntoView({ block: "nearest" })
|
|
333
|
+
}
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
if (e.key === "Enter") {
|
|
337
|
+
this._selectCompletion()
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
protected render() {
|
|
342
|
+
return html`
|
|
343
|
+
<spectric-input style=${`anchor-name:--${this.uuid};`} autocomplete="off" @input=${this._parseQuery} @keydown=${this._handleArrows}></spectric-input>
|
|
344
|
+
<div class="autocomplete" popover style=${`position-anchor: --${this.uuid};`}>
|
|
345
|
+
${this.completions.map((option: Completion, index) =>
|
|
346
|
+
html`<div @click=${() => {
|
|
347
|
+
this.completionIndex = index;
|
|
348
|
+
this._selectCompletion()
|
|
349
|
+
}} class=${this.completionIndex == index ? "option active" : "option"}><span class="optiontype ${option.type}">${option.type}</span> <span class="value">${option.value}</span> <span class="label">${option.label}</span></span> </div></div>`
|
|
350
|
+
)}
|
|
351
|
+
</div>`
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
declare global {
|
|
357
|
+
interface HTMLElementTagNameMap {
|
|
358
|
+
"spectric-query": HTMLElementTagWithEvents<SpectricQuery, QueryEventMap>
|
|
359
|
+
}
|
|
360
|
+
namespace JSX {
|
|
361
|
+
interface IntrinsicElements {
|
|
362
|
+
/**
|
|
363
|
+
* {@link SpectricQuery}
|
|
364
|
+
*/
|
|
365
|
+
"spectric-query": ReactElementWithPropsAndEvents<SpectricQuery, IQueryProps, QueryEventMap>
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
namespace React {
|
|
369
|
+
namespace JSX {
|
|
370
|
+
interface IntrinsicElements {
|
|
371
|
+
/**
|
|
372
|
+
* {@link SpectricQuery}
|
|
373
|
+
*/
|
|
374
|
+
"spectric-query": ReactElementWithPropsAndEvents<SpectricQuery, IQueryProps, QueryEventMap>;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|