ng-primitives 0.78.0 → 0.80.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.
- package/ai/README.md +3 -0
- package/ai/index.d.ts +16 -0
- package/ai/prompt-composer/prompt-composer-state.d.ts +17 -0
- package/ai/prompt-composer/prompt-composer.d.ts +23 -0
- package/ai/prompt-composer-dictation/prompt-composer-dictation-state.d.ts +17 -0
- package/ai/prompt-composer-dictation/prompt-composer-dictation.d.ts +29 -0
- package/ai/prompt-composer-input/prompt-composer-input-state.d.ts +17 -0
- package/ai/prompt-composer-input/prompt-composer-input.d.ts +16 -0
- package/ai/prompt-composer-submit/prompt-composer-submit-state.d.ts +17 -0
- package/ai/prompt-composer-submit/prompt-composer-submit.d.ts +15 -0
- package/ai/thread/thread-state.d.ts +17 -0
- package/ai/thread/thread.d.ts +23 -0
- package/ai/thread-message/thread-message-state.d.ts +17 -0
- package/ai/thread-message/thread-message.d.ts +11 -0
- package/ai/thread-suggestion/thread-suggestion-state.d.ts +17 -0
- package/ai/thread-suggestion/thread-suggestion.d.ts +14 -0
- package/ai/thread-viewport/thread-viewport-state.d.ts +17 -0
- package/ai/thread-viewport/thread-viewport.d.ts +34 -0
- package/combobox/combobox/combobox.d.ts +32 -0
- package/combobox/utils.d.ts +9 -0
- package/fesm2022/ng-primitives-ai.mjs +593 -0
- package/fesm2022/ng-primitives-ai.mjs.map +1 -0
- package/fesm2022/ng-primitives-combobox.mjs +187 -7
- package/fesm2022/ng-primitives-combobox.mjs.map +1 -1
- package/package.json +23 -19
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ng-primitives-ai.mjs","sources":["../../../../packages/ng-primitives/ai/src/prompt-composer/prompt-composer-state.ts","../../../../packages/ng-primitives/ai/src/thread/thread-state.ts","../../../../packages/ng-primitives/ai/src/prompt-composer-input/prompt-composer-input-state.ts","../../../../packages/ng-primitives/ai/src/prompt-composer-input/prompt-composer-input.ts","../../../../packages/ng-primitives/ai/src/prompt-composer-submit/prompt-composer-submit-state.ts","../../../../packages/ng-primitives/ai/src/prompt-composer-submit/prompt-composer-submit.ts","../../../../packages/ng-primitives/ai/src/prompt-composer/prompt-composer.ts","../../../../packages/ng-primitives/ai/src/thread-message/thread-message-state.ts","../../../../packages/ng-primitives/ai/src/thread-message/thread-message.ts","../../../../packages/ng-primitives/ai/src/thread/thread.ts","../../../../packages/ng-primitives/ai/src/prompt-composer-dictation/prompt-composer-dictation-state.ts","../../../../packages/ng-primitives/ai/src/prompt-composer-dictation/prompt-composer-dictation.ts","../../../../packages/ng-primitives/ai/src/thread-viewport/thread-viewport-state.ts","../../../../packages/ng-primitives/ai/src/thread-viewport/thread-viewport.ts","../../../../packages/ng-primitives/ai/src/thread-suggestion/thread-suggestion-state.ts","../../../../packages/ng-primitives/ai/src/thread-suggestion/thread-suggestion.ts","../../../../packages/ng-primitives/ai/src/ng-primitives-ai.ts"],"sourcesContent":["import {\n createState,\n createStateInjector,\n createStateProvider,\n createStateToken,\n} from 'ng-primitives/state';\nimport type { NgpPromptComposer } from './prompt-composer';\n\n/**\n * The state token for the PromptComposer primitive.\n */\nexport const NgpPromptComposerStateToken = createStateToken<NgpPromptComposer>('PromptComposer');\n\n/**\n * Provides the PromptComposer state.\n */\nexport const providePromptComposerState = createStateProvider(NgpPromptComposerStateToken);\n\n/**\n * Injects the PromptComposer state.\n */\nexport const injectPromptComposerState = createStateInjector<NgpPromptComposer>(\n NgpPromptComposerStateToken,\n);\n\n/**\n * The PromptComposer state registration function.\n */\nexport const promptComposerState = createState(NgpPromptComposerStateToken);\n","import {\n createState,\n createStateInjector,\n createStateProvider,\n createStateToken,\n} from 'ng-primitives/state';\nimport type { NgpThread } from './thread';\n\n/**\n * The state token for the Thread primitive.\n */\nexport const NgpThreadStateToken = createStateToken<NgpThread>('Thread');\n\n/**\n * Provides the Thread state.\n */\nexport const provideThreadState = createStateProvider(NgpThreadStateToken);\n\n/**\n * Injects the Thread state.\n */\nexport const injectThreadState = createStateInjector<NgpThread>(NgpThreadStateToken);\n\n/**\n * The Thread state registration function.\n */\nexport const threadState = createState(NgpThreadStateToken);\n","import {\n createState,\n createStateInjector,\n createStateProvider,\n createStateToken,\n} from 'ng-primitives/state';\nimport type { NgpPromptComposerInput } from './prompt-composer-input';\n\n/**\n * The state token for the PromptComposerInput primitive.\n */\nexport const NgpPromptComposerInputStateToken =\n createStateToken<NgpPromptComposerInput>('PromptComposerInput');\n\n/**\n * Provides the PromptComposerInput state.\n */\nexport const providePromptComposerInputState = createStateProvider(\n NgpPromptComposerInputStateToken,\n);\n\n/**\n * Injects the PromptComposerInput state.\n */\nexport const injectPromptComposerInputState = createStateInjector<NgpPromptComposerInput>(\n NgpPromptComposerInputStateToken,\n);\n\n/**\n * The PromptComposerInput state registration function.\n */\nexport const promptComposerInputState = createState(NgpPromptComposerInputStateToken);\n","import { Directive, HostListener } from '@angular/core';\nimport { explicitEffect, injectElementRef } from 'ng-primitives/internal';\nimport { safeTakeUntilDestroyed } from 'ng-primitives/utils';\nimport { fromEvent } from 'rxjs';\nimport { injectPromptComposerState } from '../prompt-composer/prompt-composer-state';\nimport { injectThreadState } from '../thread/thread-state';\nimport {\n promptComposerInputState,\n providePromptComposerInputState,\n} from './prompt-composer-input-state';\n\n@Directive({\n selector: 'input[ngpPromptComposerInput], textarea[ngpPromptComposerInput]',\n exportAs: 'ngpPromptComposerInput',\n providers: [providePromptComposerInputState()],\n})\nexport class NgpPromptComposerInput {\n protected readonly thread = injectThreadState();\n private readonly composer = injectPromptComposerState();\n private readonly element = injectElementRef<HTMLInputElement | HTMLTextAreaElement>();\n\n /** The state of the prompt composer input. */\n protected readonly state = promptComposerInputState<NgpPromptComposerInput>(this);\n\n constructor() {\n // set the initial state\n this.composer().prompt.set(this.element.nativeElement.value);\n\n // listen for requests to set the prompt\n this.thread()\n .requestPrompt.pipe(safeTakeUntilDestroyed())\n .subscribe(value => {\n // set the cursor to the end\n this.composer().prompt.set(value);\n this.element.nativeElement.setSelectionRange(value.length, value.length);\n this.element.nativeElement.focus();\n });\n\n // listen for changes to the text content\n fromEvent(this.element.nativeElement, 'input')\n .pipe(safeTakeUntilDestroyed())\n .subscribe(() => this.composer().prompt.set(this.element.nativeElement.value));\n\n // any time the prompt changes, update the input value if needed\n explicitEffect(\n [this.composer().prompt],\n ([prompt]) => (this.element.nativeElement.value = prompt),\n );\n }\n\n /**\n * If the user presses Enter, the form will be submitted, unless they are holding Shift.\n * This directive automatically handles that behavior.\n */\n @HostListener('keydown.enter', ['$event'])\n protected onEnterKey(event: KeyboardEvent): void {\n if (event.shiftKey) {\n return;\n }\n\n event.preventDefault();\n\n // if there is no text content, do nothing\n if (this.element.nativeElement.value.trim().length === 0) {\n return;\n }\n\n this.composer().submitPrompt();\n }\n}\n","import {\n createState,\n createStateInjector,\n createStateProvider,\n createStateToken,\n} from 'ng-primitives/state';\nimport type { NgpPromptComposerSubmit } from './prompt-composer-submit';\n\n/**\n * The state token for the PromptComposerSubmit primitive.\n */\nexport const NgpPromptComposerSubmitStateToken =\n createStateToken<NgpPromptComposerSubmit>('PromptComposerSubmit');\n\n/**\n * Provides the PromptComposerSubmit state.\n */\nexport const providePromptComposerSubmitState = createStateProvider(\n NgpPromptComposerSubmitStateToken,\n);\n\n/**\n * Injects the PromptComposerSubmit state.\n */\nexport const injectPromptComposerSubmitState = createStateInjector<NgpPromptComposerSubmit>(\n NgpPromptComposerSubmitStateToken,\n);\n\n/**\n * The PromptComposerSubmit state registration function.\n */\nexport const promptComposerSubmitState = createState(NgpPromptComposerSubmitStateToken);\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { booleanAttribute, computed, Directive, HostListener, input } from '@angular/core';\nimport { setupButton } from 'ng-primitives/button';\nimport { injectPromptComposerState } from '../prompt-composer/prompt-composer-state';\nimport {\n promptComposerSubmitState,\n providePromptComposerSubmitState,\n} from './prompt-composer-submit-state';\n\n@Directive({\n selector: 'button[ngpPromptComposerSubmit]',\n exportAs: 'ngpPromptComposerSubmit',\n providers: [providePromptComposerSubmitState()],\n host: {\n type: 'button',\n '[attr.data-prompt]': 'composer().hasPrompt() ? \"\" : null',\n '[attr.data-dictating]': 'isDictating() ? \"\" : null',\n '[attr.data-dictation-supported]': 'composer().dictationSupported ? \"\" : null',\n },\n})\nexport class NgpPromptComposerSubmit {\n protected readonly composer = injectPromptComposerState();\n\n /** Whether the submit button should be disabled */\n readonly disabled = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Whether dictation is currently active */\n readonly isDictating = computed(() => this.composer().isDictating());\n\n /** The state of the prompt composer submit. */\n protected readonly state = promptComposerSubmitState<NgpPromptComposerSubmit>(this);\n\n constructor() {\n setupButton({\n disabled: computed(() => this.state.disabled() || this.composer().hasPrompt() === false),\n });\n }\n\n @HostListener('click')\n protected onClick(): void {\n this.composer().submitPrompt();\n }\n}\n","import { computed, Directive, output, signal } from '@angular/core';\nimport { injectThreadState } from '../thread/thread-state';\nimport { promptComposerState, providePromptComposerState } from './prompt-composer-state';\n\n@Directive({\n selector: '[ngpPromptComposer]',\n exportAs: 'ngpPromptComposer',\n providers: [providePromptComposerState()],\n host: {\n '[attr.data-prompt]': 'hasPrompt() ? \"\" : null',\n '[attr.data-dictating]': 'isDictating() ? \"\" : null',\n '[attr.data-dictation-supported]': 'dictationSupported ? \"\" : null',\n },\n})\nexport class NgpPromptComposer {\n private readonly thread = injectThreadState();\n\n /** Emits whenever the user submits the prompt. */\n readonly submit = output<string>({ alias: 'ngpPromptComposerSubmit' });\n\n /** @internal Store the current prompt text. */\n readonly prompt = signal<string>('');\n\n /** @internal Track whether the prompt is currently being dictated */\n readonly isDictating = signal<boolean>(false);\n\n /** @internal Determine whether the prompt input has content */\n readonly hasPrompt = computed(() => this.prompt().trim().length > 0);\n\n /** Whether dictation is supported by the browser */\n readonly dictationSupported = !!(\n (globalThis as any).SpeechRecognition || (globalThis as any).webkitSpeechRecognition\n );\n\n /** The state of the prompt composer. */\n protected readonly state = promptComposerState<NgpPromptComposer>(this);\n\n /**\n * @internal\n * Submits the current prompt if there is content, and clears the input.\n */\n submitPrompt(): void {\n if (this.hasPrompt()) {\n this.submit.emit(this.prompt());\n this.prompt.set('');\n this.thread().scrollToBottom('smooth');\n }\n }\n}\n","import {\n createState,\n createStateInjector,\n createStateProvider,\n createStateToken,\n} from 'ng-primitives/state';\nimport type { NgpThreadMessage } from './thread-message';\n\n/**\n * The state token for the ThreadMessage primitive.\n */\nexport const NgpThreadMessageStateToken = createStateToken<NgpThreadMessage>('ThreadMessage');\n\n/**\n * Provides the ThreadMessage state.\n */\nexport const provideThreadMessageState = createStateProvider(NgpThreadMessageStateToken);\n\n/**\n * Injects the ThreadMessage state.\n */\nexport const injectThreadMessageState = createStateInjector<NgpThreadMessage>(\n NgpThreadMessageStateToken,\n);\n\n/**\n * The ThreadMessage state registration function.\n */\nexport const threadMessageState = createState(NgpThreadMessageStateToken);\n","import { DestroyRef, Directive, ElementRef, inject } from '@angular/core';\nimport { fromMutationObserver } from 'ng-primitives/internal';\nimport { safeTakeUntilDestroyed } from 'ng-primitives/utils';\nimport { injectThreadState } from '../thread/thread-state';\nimport { provideThreadMessageState, threadMessageState } from './thread-message-state';\n\n@Directive({\n selector: '[ngpThreadMessage]',\n exportAs: 'ngpThreadMessage',\n providers: [provideThreadMessageState()],\n})\nexport class NgpThreadMessage {\n private readonly elementRef = inject(ElementRef<HTMLElement>);\n private readonly destroyRef = inject(DestroyRef);\n private readonly thread = injectThreadState();\n\n /** The state of the thread message. */\n protected readonly state = threadMessageState<NgpThreadMessage>(this);\n\n constructor() {\n // Watch for content changes (like streaming text) and maintain scroll position\n fromMutationObserver(this.elementRef.nativeElement, {\n childList: true, // Watch for new/removed child nodes\n subtree: true, // Watch changes in all descendants\n characterData: true, // Watch for text content changes in text nodes\n attributes: false, // We don't care about attribute changes for content streaming\n })\n .pipe(safeTakeUntilDestroyed())\n .subscribe(() => {\n // if this is the last message, scroll to bottom\n if (this.thread().isLastMessage(this)) {\n this.thread().scrollToBottom('smooth');\n }\n });\n\n this.thread().registerMessage(this);\n this.destroyRef.onDestroy(() => this.thread().unregisterMessage(this));\n }\n}\n","import { Directive } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { NgpThreadMessage } from '../thread-message/thread-message';\nimport { provideThreadState, threadState } from './thread-state';\n\n@Directive({\n selector: '[ngpThread]',\n exportAs: 'ngpThread',\n providers: [provideThreadState()],\n})\nexport class NgpThread {\n private messages: NgpThreadMessage[] = [];\n\n /** @internal emit event to trigger scrolling to bottom */\n readonly scrollRequest = new Subject<ScrollBehavior>();\n\n /** @internal emit event to trigger setting the prompt */\n readonly requestPrompt = new Subject<string>();\n\n /** The state of the thread. */\n protected readonly state = threadState<NgpThread>(this);\n\n scrollToBottom(behavior: ScrollBehavior): void {\n this.scrollRequest.next(behavior);\n }\n\n /** @internal Register a message with the thread */\n registerMessage(message: NgpThreadMessage): void {\n this.messages.push(message);\n }\n\n /** @internal Unregister a message from the thread */\n unregisterMessage(message: NgpThreadMessage): void {\n this.messages = this.messages.filter(m => m !== message);\n }\n\n /** @internal Determine if the given message is the last message in the thread */\n isLastMessage(message: NgpThreadMessage): boolean {\n return this.messages.length > 0 && this.messages[this.messages.length - 1] === message;\n }\n\n /** @internal Set the prompt text in the associated prompt composer */\n setPrompt(value: string): void {\n this.requestPrompt.next(value);\n }\n}\n","import {\n createState,\n createStateInjector,\n createStateProvider,\n createStateToken,\n} from 'ng-primitives/state';\nimport type { NgpPromptComposerDictation } from './prompt-composer-dictation';\n\n/**\n * The state token for the PromptComposerDictation primitive.\n */\nexport const NgpPromptComposerDictationStateToken =\n createStateToken<NgpPromptComposerDictation>('PromptComposerDictation');\n\n/**\n * Provides the PromptComposerDictation state.\n */\nexport const providePromptComposerDictationState = createStateProvider(\n NgpPromptComposerDictationStateToken,\n);\n\n/**\n * Injects the PromptComposerDictation state.\n */\nexport const injectPromptComposerDictationState = createStateInjector<NgpPromptComposerDictation>(\n NgpPromptComposerDictationStateToken,\n);\n\n/**\n * The PromptComposerDictation state registration function.\n */\nexport const promptComposerDictationState = createState(NgpPromptComposerDictationStateToken);\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n booleanAttribute,\n computed,\n Directive,\n HostListener,\n input,\n OnDestroy,\n signal,\n} from '@angular/core';\nimport { setupButton } from 'ng-primitives/button';\nimport { injectPromptComposerState } from '../prompt-composer/prompt-composer-state';\nimport {\n promptComposerDictationState,\n providePromptComposerDictationState,\n} from './prompt-composer-dictation-state';\n\ndeclare global {\n interface Window {\n SpeechRecognition: any;\n webkitSpeechRecognition: any;\n }\n}\n\n@Directive({\n selector: 'button[ngpPromptComposerDictation]',\n exportAs: 'ngpPromptComposerDictation',\n providers: [providePromptComposerDictationState()],\n host: {\n type: 'button',\n '[attr.data-dictating]': 'isDictating() ? \"\" : null',\n '[attr.data-dictation-supported]': 'composer().dictationSupported ? \"\" : null',\n '[attr.data-prompt]': 'composer().hasPrompt() ? \"\" : null',\n },\n})\nexport class NgpPromptComposerDictation implements OnDestroy {\n protected readonly composer = injectPromptComposerState();\n private recognition: any = null;\n private basePrompt = signal<string>(''); // Store the prompt before dictation started\n\n /** Whether the submit button should be disabled. */\n readonly disabled = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Whether dictation is currently active */\n readonly isDictating = computed(() => this.composer().isDictating());\n\n /** The state of the prompt composer. */\n protected readonly state = promptComposerDictationState<NgpPromptComposerDictation>(this);\n\n constructor() {\n setupButton({\n disabled: computed(\n () => this.state.disabled() || this.composer().dictationSupported === false,\n ),\n });\n this.initializeSpeechRecognition();\n }\n\n ngOnDestroy(): void {\n if (this.recognition) {\n this.recognition.stop();\n this.recognition = null;\n }\n }\n\n @HostListener('click')\n protected onClick(): void {\n if (!this.recognition) {\n console.warn('Speech recognition is not supported in this browser');\n return;\n }\n\n if (this.composer().isDictating()) {\n this.stopDictation();\n } else {\n this.startDictation();\n }\n }\n\n @HostListener('document:keydown', ['$event'])\n protected onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape' && this.composer().isDictating()) {\n event.preventDefault();\n this.stopDictation();\n }\n }\n\n private initializeSpeechRecognition(): void {\n const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;\n\n if (!SpeechRecognition) {\n return;\n }\n\n this.recognition = new SpeechRecognition();\n this.recognition.continuous = true; // Enable continuous listening\n this.recognition.interimResults = true; // Enable interim results for live updates\n this.recognition.lang = 'en-US';\n\n this.recognition.onstart = () => {\n this.composer().isDictating.set(true);\n // Store the current prompt as the base\n this.basePrompt.set(this.composer().prompt());\n };\n\n this.recognition.onresult = (event: any) => {\n let interimTranscript = '';\n let finalTranscript = '';\n\n // Process all results\n for (let i = 0; i < event.results.length; i++) {\n const transcript = event.results[i][0].transcript;\n if (event.results[i].isFinal) {\n finalTranscript += transcript;\n } else {\n interimTranscript += transcript;\n }\n }\n\n // Combine base prompt with final transcript and interim transcript\n const baseText = this.basePrompt();\n const separator = baseText ? ' ' : '';\n const newPrompt = baseText + separator + finalTranscript + interimTranscript;\n\n this.composer().prompt.set(newPrompt.trim());\n };\n\n this.recognition.onend = () => {\n this.composer().isDictating.set(false);\n };\n\n this.recognition.onerror = (event: any) => {\n console.error('Speech recognition error:', event.error);\n this.composer().isDictating.set(false);\n };\n }\n\n private startDictation(): void {\n if (this.recognition && !this.composer().isDictating()) {\n this.recognition.start();\n }\n }\n\n private stopDictation(): void {\n if (this.recognition && this.composer().isDictating()) {\n this.recognition.stop();\n }\n }\n}\n","import {\n createState,\n createStateInjector,\n createStateProvider,\n createStateToken,\n} from 'ng-primitives/state';\nimport type { NgpThreadViewport } from './thread-viewport';\n\n/**\n * The state token for the ThreadViewport primitive.\n */\nexport const NgpThreadViewportStateToken = createStateToken<NgpThreadViewport>('ThreadViewport');\n\n/**\n * Provides the ThreadViewport state.\n */\nexport const provideThreadViewportState = createStateProvider(NgpThreadViewportStateToken);\n\n/**\n * Injects the ThreadViewport state.\n */\nexport const injectThreadViewportState = createStateInjector<NgpThreadViewport>(\n NgpThreadViewportStateToken,\n);\n\n/**\n * The ThreadViewport state registration function.\n */\nexport const threadViewportState = createState(NgpThreadViewportStateToken);\n","import { BooleanInput, NumberInput } from '@angular/cdk/coercion';\nimport {\n booleanAttribute,\n Directive,\n ElementRef,\n HostListener,\n inject,\n input,\n numberAttribute,\n} from '@angular/core';\nimport { fromResizeEvent } from 'ng-primitives/internal';\nimport { safeTakeUntilDestroyed } from 'ng-primitives/utils';\nimport { injectThreadState } from '../thread/thread-state';\nimport { provideThreadViewportState, threadViewportState } from './thread-viewport-state';\n\n@Directive({\n selector: '[ngpThreadViewport]',\n exportAs: 'ngpThreadViewport',\n providers: [provideThreadViewportState()],\n})\nexport class NgpThreadViewport {\n private readonly thread = injectThreadState();\n private readonly elementRef = inject(ElementRef<HTMLElement>);\n\n /**\n * The distance in pixels from the bottom of the scrollable container that is considered \"at the bottom\".\n * When the user scrolls within this threshold, the thread is treated as being at the bottom.\n * This value is used to determine whether automatic scrolling to the bottom should occur,\n * for example when new content is added or the container is resized.\n *\n * @default 70\n */\n readonly threshold = input<number, NumberInput>(70, {\n alias: 'ngpThreadViewportThreshold',\n transform: numberAttribute,\n });\n\n /**\n * Whether the thread should automatically scroll to the bottom when new content is added.\n */\n readonly autoScroll = input<boolean, BooleanInput>(true, {\n alias: 'ngpThreadViewportAutoScroll',\n transform: booleanAttribute,\n });\n\n /** Store the last known scroll position */\n private lastScrollTop = 0;\n\n /** Determine if we are at the bottom of the scrollable container (within the threshold) */\n protected isAtBottom = false;\n\n /** The state of the thread viewport. */\n protected readonly state = threadViewportState<NgpThreadViewport>(this);\n\n constructor() {\n // listen for scroll requests from the thread\n this.thread()\n .scrollRequest.pipe(safeTakeUntilDestroyed())\n .subscribe(behavior => this.scrollToBottom(behavior));\n\n fromResizeEvent(this.elementRef.nativeElement)\n .pipe(safeTakeUntilDestroyed())\n .subscribe(() => {\n if (this.isAtBottom) {\n this.scrollToBottom('instant');\n }\n this.onScroll();\n });\n }\n\n /**\n * Scroll the container to the bottom.\n * @internal\n */\n scrollToBottom(behavior: ScrollBehavior): void {\n if (!this.state.autoScroll()) {\n return;\n }\n\n this.elementRef.nativeElement.scrollTo({\n top: this.elementRef.nativeElement.scrollHeight,\n behavior,\n });\n }\n\n @HostListener('scroll')\n protected onScroll(): void {\n const element = this.elementRef.nativeElement;\n const isAtBottom = element.scrollHeight - element.scrollTop <= element.clientHeight;\n\n if (isAtBottom || this.lastScrollTop >= element.scrollTop) {\n this.isAtBottom = isAtBottom;\n }\n\n this.lastScrollTop = element.scrollTop;\n }\n}\n","import {\n createState,\n createStateInjector,\n createStateProvider,\n createStateToken,\n} from 'ng-primitives/state';\nimport type { NgpThreadSuggestion } from './thread-suggestion';\n\n/**\n * The state token for the ThreadSuggestion primitive.\n */\nexport const NgpThreadSuggestionStateToken =\n createStateToken<NgpThreadSuggestion>('ThreadSuggestion');\n\n/**\n * Provides the ThreadSuggestion state.\n */\nexport const provideThreadSuggestionState = createStateProvider(NgpThreadSuggestionStateToken);\n\n/**\n * Injects the ThreadSuggestion state.\n */\nexport const injectThreadSuggestionState = createStateInjector<NgpThreadSuggestion>(\n NgpThreadSuggestionStateToken,\n);\n\n/**\n * The ThreadSuggestion state registration function.\n */\nexport const threadSuggestionState = createState(NgpThreadSuggestionStateToken);\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { booleanAttribute, Directive, HostListener, input } from '@angular/core';\nimport { injectThreadState } from '../thread/thread-state';\nimport { provideThreadSuggestionState, threadSuggestionState } from './thread-suggestion-state';\n\n@Directive({\n selector: 'button[ngpThreadSuggestion]',\n exportAs: 'ngpThreadSuggestion',\n providers: [provideThreadSuggestionState()],\n})\nexport class NgpThreadSuggestion {\n private readonly thread = injectThreadState();\n\n /** The suggested text to display in the input field. */\n readonly suggestion = input<string>('', { alias: 'ngpThreadSuggestion' });\n\n /** Whether the suggestion should populate the prompt when clicked. */\n readonly setPromptOnClick = input<boolean, BooleanInput>(true, {\n alias: 'ngpThreadSuggestionSetPromptOnClick',\n transform: booleanAttribute,\n });\n\n /** The state of the thread suggestion. */\n protected readonly state = threadSuggestionState<NgpThreadSuggestion>(this);\n\n @HostListener('click')\n submitSuggestion(): void {\n if (this.state.setPromptOnClick() && this.state.suggestion().length > 0) {\n this.thread().setPrompt(this.state.suggestion());\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -227,7 +227,7 @@ class NgpComboboxInput {
|
|
|
227
227
|
* @internal
|
|
228
228
|
*/
|
|
229
229
|
focus() {
|
|
230
|
-
this.elementRef.nativeElement.focus();
|
|
230
|
+
this.elementRef.nativeElement.focus({ preventScroll: true });
|
|
231
231
|
}
|
|
232
232
|
highlightText() {
|
|
233
233
|
if (this.pointerFocused) {
|
|
@@ -280,6 +280,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImpo
|
|
|
280
280
|
args: ['pointerdown', ['$event']]
|
|
281
281
|
}] } });
|
|
282
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Check if all regular options (excluding 'all' and undefined) are selected.
|
|
285
|
+
* @param options All available options
|
|
286
|
+
* @param selectedValues Currently selected values
|
|
287
|
+
* @param compareWith Comparison function
|
|
288
|
+
* @returns true if all regular options are selected
|
|
289
|
+
*/
|
|
290
|
+
function areAllOptionsSelected(options, selectedValues, compareWith) {
|
|
291
|
+
const regularOptions = options.filter(opt => opt.value() !== 'all' && opt.value() !== undefined);
|
|
292
|
+
return (regularOptions.length > 0 &&
|
|
293
|
+
regularOptions.every(opt => selectedValues.some(val => compareWith(val, opt.value()))));
|
|
294
|
+
}
|
|
295
|
+
|
|
283
296
|
class NgpComboboxOption {
|
|
284
297
|
constructor() {
|
|
285
298
|
/** Access the combobox state. */
|
|
@@ -308,13 +321,25 @@ class NgpComboboxOption {
|
|
|
308
321
|
/** Whether this option is selected. */
|
|
309
322
|
this.selected = computed(() => {
|
|
310
323
|
const value = this.value();
|
|
324
|
+
const stateValue = this.state().value();
|
|
311
325
|
if (!value) {
|
|
312
326
|
return false;
|
|
313
327
|
}
|
|
328
|
+
// Handle select all functionality - only works in multiple selection mode
|
|
329
|
+
if (value === 'all') {
|
|
330
|
+
if (!this.state().multiple()) {
|
|
331
|
+
return false; // Never selected in single selection mode
|
|
332
|
+
}
|
|
333
|
+
const selectedValues = Array.isArray(stateValue) ? stateValue : [];
|
|
334
|
+
return areAllOptionsSelected(this.state().options(), selectedValues, this.state().compareWith());
|
|
335
|
+
}
|
|
336
|
+
if (!stateValue) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
314
339
|
if (this.state().multiple()) {
|
|
315
|
-
return (Array.isArray(
|
|
340
|
+
return (Array.isArray(stateValue) && stateValue.some(v => this.state().compareWith()(value, v)));
|
|
316
341
|
}
|
|
317
|
-
return this.state().compareWith()(value,
|
|
342
|
+
return this.state().compareWith()(value, stateValue);
|
|
318
343
|
});
|
|
319
344
|
this.state().registerOption(this);
|
|
320
345
|
setupInteractions({
|
|
@@ -661,6 +686,18 @@ class NgpCombobox {
|
|
|
661
686
|
this.closeDropdown();
|
|
662
687
|
return;
|
|
663
688
|
}
|
|
689
|
+
// Handle select all functionality - only works in multiple selection mode
|
|
690
|
+
if (option.value() === 'all') {
|
|
691
|
+
if (!this.state.multiple()) {
|
|
692
|
+
return; // Do nothing in single selection mode
|
|
693
|
+
}
|
|
694
|
+
// Get currently visible regular options (respects filtering)
|
|
695
|
+
const regularOptions = this.options().filter(opt => opt.value() !== 'all' && opt.value() !== undefined);
|
|
696
|
+
const allValues = regularOptions.map(opt => opt.value());
|
|
697
|
+
this.state.value.set(allValues);
|
|
698
|
+
this.valueChange.emit(allValues);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
664
701
|
if (this.state.multiple()) {
|
|
665
702
|
// if the option is already selected, do nothing
|
|
666
703
|
if (this.isOptionSelected(option)) {
|
|
@@ -692,6 +729,15 @@ class NgpCombobox {
|
|
|
692
729
|
if (!this.state.multiple() && !this.state.allowDeselect()) {
|
|
693
730
|
return;
|
|
694
731
|
}
|
|
732
|
+
// Handle select all for deselect all functionality - only works in multiple selection mode
|
|
733
|
+
if (option.value() === 'all') {
|
|
734
|
+
if (!this.state.multiple()) {
|
|
735
|
+
return; // Do nothing in single selection mode
|
|
736
|
+
}
|
|
737
|
+
this.state.value.set([]);
|
|
738
|
+
this.valueChange.emit([]);
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
695
741
|
if (this.state.multiple()) {
|
|
696
742
|
const values = this.state.value() ?? [];
|
|
697
743
|
const newValue = values.filter(v => !this.state.compareWith()(v, option.value()));
|
|
@@ -714,6 +760,19 @@ class NgpCombobox {
|
|
|
714
760
|
if (this.state.disabled()) {
|
|
715
761
|
return;
|
|
716
762
|
}
|
|
763
|
+
// Handle select all for select/deselect all functionality - only works in multiple selection mode
|
|
764
|
+
if (option.value() === 'all') {
|
|
765
|
+
if (!this.state.multiple()) {
|
|
766
|
+
return; // Do nothing in single selection mode
|
|
767
|
+
}
|
|
768
|
+
if (this.isOptionSelected(option)) {
|
|
769
|
+
this.deselectOption(option);
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
this.selectOption(option);
|
|
773
|
+
}
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
717
776
|
if (this.state.multiple()) {
|
|
718
777
|
// In multiple selection mode, always allow toggling
|
|
719
778
|
if (this.isOptionSelected(option)) {
|
|
@@ -745,14 +804,23 @@ class NgpCombobox {
|
|
|
745
804
|
if (this.state.disabled()) {
|
|
746
805
|
return false;
|
|
747
806
|
}
|
|
807
|
+
const optionValue = option.value();
|
|
748
808
|
const value = this.state.value();
|
|
809
|
+
// Handle select all functionality - only works in multiple selection mode
|
|
810
|
+
if (optionValue === 'all') {
|
|
811
|
+
if (!this.state.multiple()) {
|
|
812
|
+
return false; // Never selected in single selection mode
|
|
813
|
+
}
|
|
814
|
+
const selectedValues = Array.isArray(value) ? value : [];
|
|
815
|
+
return areAllOptionsSelected(this.options(), selectedValues, this.state.compareWith());
|
|
816
|
+
}
|
|
749
817
|
if (!value) {
|
|
750
818
|
return false;
|
|
751
819
|
}
|
|
752
820
|
if (this.state.multiple()) {
|
|
753
|
-
return value && value.some(v => this.state.compareWith()(
|
|
821
|
+
return value && value.some(v => this.state.compareWith()(optionValue, v));
|
|
754
822
|
}
|
|
755
|
-
return this.state.compareWith()(
|
|
823
|
+
return this.state.compareWith()(optionValue, value);
|
|
756
824
|
}
|
|
757
825
|
/**
|
|
758
826
|
* Activate the next option in the list if there is one.
|
|
@@ -851,8 +919,113 @@ class NgpCombobox {
|
|
|
851
919
|
unregisterOption(option) {
|
|
852
920
|
this.options.update(options => options.filter(o => o !== option));
|
|
853
921
|
}
|
|
922
|
+
/**
|
|
923
|
+
* Focus the combobox.
|
|
924
|
+
* When an input element is present, it will be focused.
|
|
925
|
+
* Otherwise, the combobox element itself will be focused.
|
|
926
|
+
* This enables keyboard navigation for comboboxes without input elements.
|
|
927
|
+
* @internal
|
|
928
|
+
*/
|
|
929
|
+
focus() {
|
|
930
|
+
if (this.input()) {
|
|
931
|
+
this.input()?.focus();
|
|
932
|
+
}
|
|
933
|
+
else {
|
|
934
|
+
this.elementRef.nativeElement.focus();
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* Handle keydown events for keyboard navigation and accessibility.
|
|
939
|
+
* Supports:
|
|
940
|
+
* - Arrow Down: Open dropdown or navigate to next option
|
|
941
|
+
* - Arrow Up: Open dropdown or navigate to previous option
|
|
942
|
+
* - Home: Navigate to first option
|
|
943
|
+
* - End: Navigate to last option
|
|
944
|
+
* - Enter: Select the currently active option
|
|
945
|
+
* - Escape: Close the dropdown
|
|
946
|
+
* @param event - The keyboard event
|
|
947
|
+
* @internal
|
|
948
|
+
*/
|
|
949
|
+
handleKeydown(event) {
|
|
950
|
+
// If the event originated from the input element, let the input handle it
|
|
951
|
+
if (this.input() && event.target === this.input()?.elementRef.nativeElement) {
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
switch (event.key) {
|
|
955
|
+
case 'ArrowDown':
|
|
956
|
+
if (this.open()) {
|
|
957
|
+
this.activateNextOption();
|
|
958
|
+
}
|
|
959
|
+
else {
|
|
960
|
+
this.openDropdown();
|
|
961
|
+
}
|
|
962
|
+
event.preventDefault();
|
|
963
|
+
break;
|
|
964
|
+
case 'ArrowUp':
|
|
965
|
+
if (this.open()) {
|
|
966
|
+
this.activatePreviousOption();
|
|
967
|
+
}
|
|
968
|
+
else {
|
|
969
|
+
this.openDropdown();
|
|
970
|
+
// Use setTimeout to ensure dropdown is rendered before selecting last item
|
|
971
|
+
setTimeout(() => this.activeDescendantManager.last());
|
|
972
|
+
}
|
|
973
|
+
event.preventDefault();
|
|
974
|
+
break;
|
|
975
|
+
case 'Home':
|
|
976
|
+
if (this.open()) {
|
|
977
|
+
this.activeDescendantManager.first();
|
|
978
|
+
}
|
|
979
|
+
event.preventDefault();
|
|
980
|
+
break;
|
|
981
|
+
case 'End':
|
|
982
|
+
if (this.open()) {
|
|
983
|
+
this.activeDescendantManager.last();
|
|
984
|
+
}
|
|
985
|
+
event.preventDefault();
|
|
986
|
+
break;
|
|
987
|
+
case 'Enter':
|
|
988
|
+
if (this.open()) {
|
|
989
|
+
this.selectOption(this.activeDescendantManager.activeItem());
|
|
990
|
+
}
|
|
991
|
+
event.preventDefault();
|
|
992
|
+
break;
|
|
993
|
+
case 'Escape':
|
|
994
|
+
if (this.open()) {
|
|
995
|
+
this.closeDropdown();
|
|
996
|
+
}
|
|
997
|
+
event.preventDefault();
|
|
998
|
+
break;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Handle blur events to manage dropdown closing behavior.
|
|
1003
|
+
* The dropdown will remain open if focus moves to:
|
|
1004
|
+
* - The dropdown itself
|
|
1005
|
+
* - The combobox button
|
|
1006
|
+
* - The combobox input
|
|
1007
|
+
* Otherwise, the dropdown will be closed.
|
|
1008
|
+
* @param event - The focus event
|
|
1009
|
+
* @internal
|
|
1010
|
+
*/
|
|
1011
|
+
onBlur(event) {
|
|
1012
|
+
const relatedTarget = event.relatedTarget;
|
|
1013
|
+
// if the blur was caused by focus moving to the dropdown, don't close
|
|
1014
|
+
if (relatedTarget && this.dropdown()?.elementRef.nativeElement.contains(relatedTarget)) {
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
// if the blur was caused by focus moving to the button, don't close
|
|
1018
|
+
if (relatedTarget && this.button()?.elementRef.nativeElement.contains(relatedTarget)) {
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
// if the blur was caused by focus moving to the input, don't close
|
|
1022
|
+
if (relatedTarget && this.input()?.elementRef.nativeElement === relatedTarget) {
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
this.closeDropdown();
|
|
1026
|
+
}
|
|
854
1027
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpCombobox, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
855
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.11", type: NgpCombobox, isStandalone: true, selector: "[ngpCombobox]", inputs: { value: { classPropertyName: "value", publicName: "ngpComboboxValue", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "ngpComboboxMultiple", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "ngpComboboxDisabled", isSignal: true, isRequired: false, transformFunction: null }, allowDeselect: { classPropertyName: "allowDeselect", publicName: "ngpComboboxAllowDeselect", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "ngpComboboxCompareWith", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "ngpComboboxDropdownPlacement", isSignal: true, isRequired: false, transformFunction: null }, container: { classPropertyName: "container", publicName: "ngpComboboxDropdownContainer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "ngpComboboxValueChange", openChange: "ngpComboboxOpenChange" }, host: { properties: { "attr.data-open": "state.open() ? \"\" : undefined", "attr.data-disabled": "state.disabled() ? \"\" : undefined", "attr.data-multiple": "state.multiple() ? \"\" : undefined", "attr.data-invalid": "controlStatus()?.invalid ? \"\" : undefined", "attr.data-valid": "controlStatus()?.valid ? \"\" : undefined", "attr.data-touched": "controlStatus()?.touched ? \"\" : undefined", "attr.data-pristine": "controlStatus()?.pristine ? \"\" : undefined", "attr.data-dirty": "controlStatus()?.dirty ? \"\" : undefined", "attr.data-pending": "controlStatus()?.pending ? \"\" : undefined" } }, providers: [provideComboboxState()], exportAs: ["ngpCombobox"], ngImport: i0 }); }
|
|
1028
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.11", type: NgpCombobox, isStandalone: true, selector: "[ngpCombobox]", inputs: { value: { classPropertyName: "value", publicName: "ngpComboboxValue", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "ngpComboboxMultiple", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "ngpComboboxDisabled", isSignal: true, isRequired: false, transformFunction: null }, allowDeselect: { classPropertyName: "allowDeselect", publicName: "ngpComboboxAllowDeselect", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "ngpComboboxCompareWith", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "ngpComboboxDropdownPlacement", isSignal: true, isRequired: false, transformFunction: null }, container: { classPropertyName: "container", publicName: "ngpComboboxDropdownContainer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "ngpComboboxValueChange", openChange: "ngpComboboxOpenChange" }, host: { listeners: { "keydown": "handleKeydown($event)", "blur": "onBlur($event)" }, properties: { "attr.tabindex": "input() ? -1 : (state.disabled() ? -1 : 0)", "attr.data-open": "state.open() ? \"\" : undefined", "attr.data-disabled": "state.disabled() ? \"\" : undefined", "attr.data-multiple": "state.multiple() ? \"\" : undefined", "attr.data-invalid": "controlStatus()?.invalid ? \"\" : undefined", "attr.data-valid": "controlStatus()?.valid ? \"\" : undefined", "attr.data-touched": "controlStatus()?.touched ? \"\" : undefined", "attr.data-pristine": "controlStatus()?.pristine ? \"\" : undefined", "attr.data-dirty": "controlStatus()?.dirty ? \"\" : undefined", "attr.data-pending": "controlStatus()?.pending ? \"\" : undefined" } }, providers: [provideComboboxState()], exportAs: ["ngpCombobox"], ngImport: i0 }); }
|
|
856
1029
|
}
|
|
857
1030
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpCombobox, decorators: [{
|
|
858
1031
|
type: Directive,
|
|
@@ -861,6 +1034,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImpo
|
|
|
861
1034
|
exportAs: 'ngpCombobox',
|
|
862
1035
|
providers: [provideComboboxState()],
|
|
863
1036
|
host: {
|
|
1037
|
+
'[attr.tabindex]': 'input() ? -1 : (state.disabled() ? -1 : 0)',
|
|
864
1038
|
'[attr.data-open]': 'state.open() ? "" : undefined',
|
|
865
1039
|
'[attr.data-disabled]': 'state.disabled() ? "" : undefined',
|
|
866
1040
|
'[attr.data-multiple]': 'state.multiple() ? "" : undefined',
|
|
@@ -872,7 +1046,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImpo
|
|
|
872
1046
|
'[attr.data-pending]': 'controlStatus()?.pending ? "" : undefined',
|
|
873
1047
|
},
|
|
874
1048
|
}]
|
|
875
|
-
}], ctorParameters: () => []
|
|
1049
|
+
}], ctorParameters: () => [], propDecorators: { handleKeydown: [{
|
|
1050
|
+
type: HostListener,
|
|
1051
|
+
args: ['keydown', ['$event']]
|
|
1052
|
+
}], onBlur: [{
|
|
1053
|
+
type: HostListener,
|
|
1054
|
+
args: ['blur', ['$event']]
|
|
1055
|
+
}] } });
|
|
876
1056
|
|
|
877
1057
|
/**
|
|
878
1058
|
* Generated bundle index. Do not edit.
|