@api-client/ui 0.5.18 → 0.5.20

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.
@@ -123,42 +123,28 @@ class CodeEditorDemo extends DemoPage {
123
123
 
124
124
  <code-editor
125
125
  label="Code Editor"
126
- supporting-text="Type function names or {{fnName}} to see autocomplete"
126
+ supportingtext="Type function names or {{fnName}} to see autocomplete"
127
127
  .value=${this.editorValue}
128
128
  .functionSchemas=${this.functions}
129
129
  .suggestions=${this.suggestions}
130
- @function-insert=${this.handleFunctionInsert}
131
- @suggestion-insert=${this.handleSuggestionInsert}
130
+ @functioninsert=${this.handleFunctionInsert}
131
+ @suggestioninsert=${this.handleSuggestionInsert}
132
132
  @input=${this.handleInput}
133
133
  @change=${this.handleChange}
134
- show-documentation
135
- @function-documentation="${this.handleFunctionDocumentation}"
134
+ showdocumentation
135
+ @docsrequest="${this.handleFunctionDocumentation}"
136
136
  ></code-editor>
137
137
 
138
138
  ${this.output ? html`<p><strong>Output:</strong> ${this.output}</p>` : ''}
139
139
  </section>
140
140
 
141
- <section class="demo-section">
142
- <h2 class="display-large">Dark Theme</h2>
143
- <p>The same editor with dark theme enabled.</p>
144
-
145
- <code-editor
146
- label="Dark Theme Editor"
147
- supporting-text="Dark theme variant"
148
- .value=${'// Dark theme example\nconst theme = "dark"'}
149
- .functionSchemas=${this.functions}
150
- .suggestions=${this.suggestions}
151
- dark-theme
152
- ></code-editor>
153
- </section>
154
-
155
141
  <section class="demo-section">
156
142
  <h2 class="display-large">Disabled State</h2>
157
143
  <p>A disabled editor for read-only content.</p>
158
144
 
159
145
  <code-editor
160
146
  label="Disabled Editor"
161
- supporting-text="This editor is disabled"
147
+ supportingtext="This editor is disabled"
162
148
  .value=${'// This editor is disabled\nconst readOnly = true'}
163
149
  .functionSchemas=${this.functions}
164
150
  .suggestions=${this.suggestions}
@@ -172,7 +158,7 @@ class CodeEditorDemo extends DemoPage {
172
158
 
173
159
  <code-editor
174
160
  label="Error Editor"
175
- supporting-text="This editor has an error"
161
+ supportingtext="This editor has an error"
176
162
  .value=${'// This editor has an error\nconst invalid = true'}
177
163
  .functionSchemas=${this.functions}
178
164
  .suggestions=${this.suggestions}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@api-client/ui",
3
- "version": "0.5.18",
3
+ "version": "0.5.20",
4
4
  "description": "Internal UI component library for the API Client ecosystem.",
5
5
  "license": "UNLICENSED",
6
6
  "main": "build/src/index.js",
@@ -186,7 +186,6 @@
186
186
  "@codemirror/language": "^6.11.2",
187
187
  "@codemirror/lint": "^6.8.5",
188
188
  "@codemirror/state": "^6.5.2",
189
- "@codemirror/theme-one-dark": "^6.1.3",
190
189
  "@codemirror/view": "^6.38.0",
191
190
  "@github/relative-time-element": "^4.4.6",
192
191
  "@material/web": "^2.3.0",
@@ -29,8 +29,8 @@ import '@api-client/ui/elements/code-editor/code-editor.js'
29
29
  .value=${this.code}
30
30
  .functionSchemas=${this.functions}
31
31
  .suggestions=${this.suggestions}
32
- @function-insert=${this.handleFunctionInsert}
33
- @suggestion-insert=${this.handleSuggestionInsert}
32
+ @functioninsert=${this.handleFunctionInsert}
33
+ @suggestioninsert=${this.handleSuggestionInsert}
34
34
  @input=${this.handleInput}
35
35
  ></code-editor>
36
36
  ```
@@ -84,8 +84,8 @@ const suggestions: Suggestion[] = [
84
84
 
85
85
  The component dispatches several events:
86
86
 
87
- - `function-insert`: When a function is inserted via autocomplete
88
- - `suggestion-insert`: When a suggestion is inserted as a pill
87
+ - `functioninsert`: When a function is inserted via autocomplete
88
+ - `suggestioninsert`: When a suggestion is inserted as a pill
89
89
  - `input`: When the editor content changes (standard input event)
90
90
  - `change`: When the editor loses focus and content has changed
91
91
 
@@ -129,6 +129,7 @@ code-editor {
129
129
  ## Accessibility
130
130
 
131
131
  The component includes:
132
+
132
133
  - Proper ARIA attributes for screen readers
133
134
  - Keyboard navigation support
134
135
  - Focus management
@@ -154,7 +155,7 @@ The component includes:
154
155
  label="Code with Functions"
155
156
  .value=${this.code}
156
157
  .functionSchemas=${this.functions}
157
- @function-insert=${this.onFunctionInsert}
158
+ @functioninsert=${this.onFunctionInsert}
158
159
  >
159
160
  </code-editor>
160
161
  ```
@@ -166,7 +167,7 @@ The component includes:
166
167
  label="Code with Mentions"
167
168
  .value=${this.code}
168
169
  .suggestions=${this.users}
169
- @suggestion-insert=${this.onSuggestionInsert}
170
+ @suggestioninsert=${this.onSuggestionInsert}
170
171
  >
171
172
  </code-editor>
172
173
  ```
@@ -189,6 +190,7 @@ A comprehensive demo is available at `/demo/elements/code-editor/` when running
189
190
  ## Browser Support
190
191
 
191
192
  The component works in all modern browsers that support:
193
+
192
194
  - ES2020+ features
193
195
  - Web Components
194
196
  - CSS Custom Properties
@@ -197,6 +199,7 @@ The component works in all modern browsers that support:
197
199
  ## Contributing
198
200
 
199
201
  When contributing to this component, please follow the established patterns:
202
+
200
203
  - Use TypeScript for type safety
201
204
  - Follow the existing code style
202
205
  - Include tests for new features
@@ -12,7 +12,6 @@ import {
12
12
  } from '@codemirror/autocomplete'
13
13
  import { javascript } from '@codemirror/lang-javascript'
14
14
  import { syntaxHighlighting, defaultHighlightStyle } from '@codemirror/language'
15
- import { oneDark } from '@codemirror/theme-one-dark'
16
15
  import { keymap } from '@codemirror/view'
17
16
  import { defaultKeymap } from '@codemirror/commands'
18
17
  import {
@@ -42,9 +41,9 @@ import '../../../md/button/ui-button.js'
42
41
  * - Keyboard navigation
43
42
  * - Accessibility support
44
43
  *
45
- * @fires function-insert - When a function is inserted
46
- * @fires suggestion-insert - When a suggestion is inserted
47
- * @fires function-documentation - When documentation is requested for a function
44
+ * @fires functioninsert - When a function is inserted
45
+ * @fires suggestioninsert - When a suggestion is inserted
46
+ * @fires docsrequest - When documentation is requested for a function
48
47
  * @fires input - When the editor content changes
49
48
  * @fires change - When the editor loses focus and content has changed
50
49
  */
@@ -69,7 +68,7 @@ export default class CodeEditor extends LitElement {
69
68
  * Supporting text displayed below the editor
70
69
  * @attribute
71
70
  */
72
- @property({ type: String, attribute: 'supporting-text' })
71
+ @property({ type: String })
73
72
  accessor supportingText = ''
74
73
 
75
74
  /**
@@ -141,12 +140,6 @@ export default class CodeEditor extends LitElement {
141
140
  @property({ type: Array, attribute: false })
142
141
  accessor suggestions: Suggestion[] = []
143
142
 
144
- /**
145
- * Whether to use dark theme
146
- */
147
- @property({ type: Boolean, attribute: 'dark-theme' })
148
- accessor darkTheme = false
149
-
150
143
  /**
151
144
  * Programming language for syntax highlighting
152
145
  * @attribute
@@ -156,9 +149,9 @@ export default class CodeEditor extends LitElement {
156
149
 
157
150
  /**
158
151
  * Whether to show documentation links/buttons in function tooltips and autocomplete
159
- * @attribute show-documentation
152
+ * @attribute
160
153
  */
161
- @property({ type: Boolean, attribute: 'show-documentation' })
154
+ @property({ type: Boolean })
162
155
  accessor showDocumentation = false
163
156
 
164
157
  @query('.editor-container')
@@ -265,11 +258,6 @@ export default class CodeEditor extends LitElement {
265
258
  extensions.push(javascript())
266
259
  }
267
260
 
268
- // Add theme
269
- if (this.darkTheme) {
270
- extensions.push(oneDark)
271
- }
272
-
273
261
  // Add placeholder
274
262
  if (this.placeholder) {
275
263
  extensions.push(
@@ -578,7 +566,7 @@ export default class CodeEditor extends LitElement {
578
566
  * Dispatch function insert event
579
567
  */
580
568
  private dispatchFunctionInsert(functionSchema: FunctionSchema, position: number): void {
581
- const event = new CustomEvent<FunctionInsertEvent>('function-insert', {
569
+ const event = new CustomEvent<FunctionInsertEvent>('functioninsert', {
582
570
  detail: { functionSchema, position },
583
571
  bubbles: true,
584
572
  })
@@ -589,7 +577,7 @@ export default class CodeEditor extends LitElement {
589
577
  * Dispatch suggestion insert event
590
578
  */
591
579
  private dispatchSuggestionInsert(suggestion: Suggestion, position: number): void {
592
- const event = new CustomEvent<SuggestionInsertEvent>('suggestion-insert', {
580
+ const event = new CustomEvent<SuggestionInsertEvent>('suggestioninsert', {
593
581
  detail: { suggestion, position },
594
582
  bubbles: true,
595
583
  })
@@ -600,7 +588,7 @@ export default class CodeEditor extends LitElement {
600
588
  * Dispatch function documentation event
601
589
  */
602
590
  private dispatchFunctionDocumentation(functionSchema: FunctionSchema): void {
603
- const event = new CustomEvent<FunctionDocumentationEvent>('function-documentation', {
591
+ const event = new CustomEvent<FunctionDocumentationEvent>('docsrequest', {
604
592
  detail: { functionSchema },
605
593
  bubbles: true,
606
594
  })
@@ -24,6 +24,7 @@ export interface UiDialogClosingReason {
24
24
  }
25
25
 
26
26
  interface DialogEventMap {
27
+ closing: CustomEvent<UiDialogClosingReason>
27
28
  close: CustomEvent<UiDialogClosingReason>
28
29
  }
29
30
 
@@ -75,6 +76,8 @@ export type RenderFunction = () => TemplateResult
75
76
  * @slot title - The slot to place the dialog title. Do not put elements here, just the text.
76
77
  * @slot button - The slot to place the dialog buttons. Use the `confirm` or `dismiss`
77
78
  * buttons to automatically close the dialog.
79
+ * @fires closing - A cancelable, non-bubbling event with the `UiDialogClosingReason` as the detail,
80
+ * dispatched before the dialog closes. If prevented, the dialog will not close.
78
81
  * @fires close - A non-bubbling, non-cancellable event with the `UiDialogClosingReason` as the detail.
79
82
  */
80
83
  export default class UiDialog extends UiElement implements TypedEvents<DialogEventMap> {
@@ -349,13 +352,29 @@ export default class UiDialog extends UiElement implements TypedEvents<DialogEve
349
352
  if (!['dismiss', 'confirm'].includes(value)) {
350
353
  return
351
354
  }
352
- this.open = false
355
+
353
356
  const detail: UiDialogClosingReason = {
354
357
  cancelled: value === 'dismiss',
355
358
  }
356
359
  if (this.dialogValue !== undefined) {
357
360
  detail.value = this.dialogValue
358
361
  }
362
+
363
+ // Dispatch cancelable closing event first
364
+ const closingEvent = new CustomEvent<UiDialogClosingReason>('closing', {
365
+ cancelable: true,
366
+ composed: false,
367
+ bubbles: false,
368
+ detail,
369
+ })
370
+ const canClose = this.dispatchEvent(closingEvent)
371
+
372
+ // Only proceed with closing if the event wasn't canceled
373
+ if (!canClose) {
374
+ return
375
+ }
376
+
377
+ this.open = false
359
378
  this.dispatchEvent(
360
379
  new CustomEvent<UiDialogClosingReason>('close', {
361
380
  composed: true,
@@ -368,8 +387,37 @@ export default class UiDialog extends UiElement implements TypedEvents<DialogEve
368
387
  if (!this.open) {
369
388
  return
370
389
  }
390
+
391
+ const detail: UiDialogClosingReason = {
392
+ cancelled: true,
393
+ }
394
+ if (this.dialogValue !== undefined) {
395
+ detail.value = this.dialogValue
396
+ }
397
+
398
+ // Dispatch cancelable closing event first
399
+ const closingEvent = new CustomEvent<UiDialogClosingReason>('closing', {
400
+ cancelable: true,
401
+ composed: false,
402
+ bubbles: false,
403
+ detail,
404
+ })
405
+ const canClose = this.dispatchEvent(closingEvent)
406
+
407
+ // Only proceed with closing if the event wasn't canceled
408
+ if (!canClose) {
409
+ // If closing was prevented, reopen the dialog
410
+ this.dialog.showModal()
411
+ return
412
+ }
413
+
371
414
  this.open = false
372
- this.handleInteraction('dismiss')
415
+ this.dispatchEvent(
416
+ new CustomEvent<UiDialogClosingReason>('close', {
417
+ composed: true,
418
+ detail,
419
+ })
420
+ )
373
421
  }
374
422
 
375
423
  protected handleDismiss(): void {
@@ -42,7 +42,7 @@ describe('CodeEditor - Accessibility', () => {
42
42
  return fixture(html`
43
43
  <code-editor
44
44
  label="Accessible Code Editor"
45
- supporting-text="Enter your code with accessibility support"
45
+ supportingtext="Enter your code with accessibility support"
46
46
  placeholder="Type your code here..."
47
47
  .functionSchemas="${sampleFunctionSchemas}"
48
48
  .suggestions="${sampleSuggestions}"
@@ -54,7 +54,7 @@ describe('CodeEditor - Accessibility', () => {
54
54
  return fixture(html`
55
55
  <code-editor
56
56
  label="Code Editor with Documentation"
57
- show-documentation
57
+ showdocumentation
58
58
  .functionSchemas="${sampleFunctionSchemas}"
59
59
  ></code-editor>
60
60
  `)
@@ -245,33 +245,6 @@ describe('CodeEditor - Accessibility', () => {
245
245
  })
246
246
  })
247
247
 
248
- describe('High Contrast and Theme Support', () => {
249
- it('should support dark theme for accessibility', async () => {
250
- const el = await accessibleFixture()
251
- el.darkTheme = true
252
- await nextFrame()
253
-
254
- // Wait for CodeMirror to apply theme
255
- await aTimeout(100)
256
-
257
- assert.isTrue(el.darkTheme)
258
- })
259
-
260
- it('should maintain readability in different themes', async () => {
261
- const el = await accessibleFixture()
262
- await nextFrame()
263
-
264
- // Test both light and dark themes
265
- el.darkTheme = false
266
- await nextFrame()
267
- assert.isFalse(el.darkTheme)
268
-
269
- el.darkTheme = true
270
- await nextFrame()
271
- assert.isTrue(el.darkTheme)
272
- })
273
- })
274
-
275
248
  describe('Touch and Mobile Accessibility', () => {
276
249
  it.skip('should be usable on touch devices', async () => {
277
250
  const el = await accessibleFixture()
@@ -77,7 +77,7 @@ describe('CodeEditor', () => {
77
77
  return fixture(html`
78
78
  <code-editor
79
79
  label="Test Editor"
80
- supporting-text="Enter your code here"
80
+ supportingtext="Enter your code here"
81
81
  placeholder="Type here..."
82
82
  .functionSchemas="${sampleFunctionSchemas}"
83
83
  .suggestions="${sampleSuggestions}"
@@ -88,7 +88,7 @@ describe('CodeEditor', () => {
88
88
  async function documentationFixture(): Promise<CodeEditorElement> {
89
89
  return fixture(html`
90
90
  <code-editor
91
- show-documentation
91
+ showdocumentation
92
92
  .functionSchemas="${sampleFunctionSchemas}"
93
93
  .suggestions="${sampleSuggestions}"
94
94
  ></code-editor>
@@ -106,7 +106,6 @@ describe('CodeEditor', () => {
106
106
  assert.isFalse(el.required)
107
107
  assert.equal(el.placeholder, '')
108
108
  assert.equal(el.value, '')
109
- assert.isFalse(el.darkTheme)
110
109
  assert.equal(el.language, 'javascript')
111
110
  assert.isFalse(el.showDocumentation)
112
111
  assert.deepEqual(el.functionSchemas, [])
@@ -123,7 +122,6 @@ describe('CodeEditor', () => {
123
122
  el.required = true
124
123
  el.placeholder = 'Test Placeholder'
125
124
  el.value = 'test code'
126
- el.darkTheme = true
127
125
  el.language = 'python'
128
126
  el.showDocumentation = true
129
127
  el.functionSchemas = sampleFunctionSchemas
@@ -138,7 +136,6 @@ describe('CodeEditor', () => {
138
136
  assert.isTrue(el.required)
139
137
  assert.equal(el.placeholder, 'Test Placeholder')
140
138
  assert.equal(el.value, 'test code')
141
- assert.isTrue(el.darkTheme)
142
139
  assert.equal(el.language, 'python')
143
140
  assert.isTrue(el.showDocumentation)
144
141
  assert.deepEqual(el.functionSchemas, sampleFunctionSchemas)
@@ -342,7 +339,7 @@ describe('CodeEditor', () => {
342
339
  })
343
340
 
344
341
  describe('Function Events', () => {
345
- it('should dispatch function-insert event through user interaction', async () => {
342
+ it('should dispatch functioninsert event through user interaction', async () => {
346
343
  const el = await configuredFixture()
347
344
  await nextFrame()
348
345
 
@@ -351,33 +348,33 @@ describe('CodeEditor', () => {
351
348
 
352
349
  // Create a spy to capture the event
353
350
  const eventSpy = sinon.spy()
354
- el.addEventListener('function-insert', eventSpy)
351
+ el.addEventListener('functioninsert', eventSpy)
355
352
 
356
353
  // Note: In a real test, this would be triggered by CodeMirror autocompletion
357
354
  // For now, we test that the event listener is properly set up
358
355
  assert.isFalse(eventSpy.called)
359
356
  })
360
357
 
361
- it('should dispatch suggestion-insert event through user interaction', async () => {
358
+ it('should dispatch suggestioninsert event through user interaction', async () => {
362
359
  const el = await configuredFixture()
363
360
  await nextFrame()
364
361
 
365
362
  // Create a spy to capture the event
366
363
  const eventSpy = sinon.spy()
367
- el.addEventListener('suggestion-insert', eventSpy)
364
+ el.addEventListener('suggestioninsert', eventSpy)
368
365
 
369
366
  // Note: In a real test, this would be triggered by CodeMirror autocompletion
370
367
  // For now, we test that the event listener is properly set up
371
368
  assert.isFalse(eventSpy.called)
372
369
  })
373
370
 
374
- it('should have function-documentation event listener when showDocumentation is true', async () => {
371
+ it('should have docsrequest event listener when showDocumentation is true', async () => {
375
372
  const el = await documentationFixture()
376
373
  await nextFrame()
377
374
 
378
375
  // Create a spy to capture the event
379
376
  const eventSpy = sinon.spy()
380
- el.addEventListener('function-documentation', eventSpy)
377
+ el.addEventListener('docsrequest', eventSpy)
381
378
 
382
379
  // Test that the element is configured to dispatch this event
383
380
  assert.isTrue(el.showDocumentation)
@@ -487,13 +484,13 @@ describe('CodeEditor', () => {
487
484
  assert.isAtLeast(el.functionSchemas.length, 1)
488
485
  })
489
486
 
490
- it('should dispatch function-documentation event when documentation is enabled', async () => {
487
+ it('should dispatch docsrequest event when documentation is enabled', async () => {
491
488
  const el = await documentationFixture()
492
489
  await nextFrame()
493
490
  await aTimeout(100) // Wait for CodeMirror initialization
494
491
 
495
492
  const eventSpy = sinon.spy()
496
- el.addEventListener('function-documentation', eventSpy)
493
+ el.addEventListener('docsrequest', eventSpy)
497
494
 
498
495
  // Access the private method through bracket notation to avoid TypeScript errors
499
496
  const functionSchema = sampleFunctionSchemas[0]