@rt-tools/ui-kit-v2 0.34.4 → 0.35.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/fesm2022/rt-tools-ui-kit-v2-ai-prompt-input.mjs +574 -0
- package/fesm2022/rt-tools-ui-kit-v2-ai-prompt-input.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-aside.mjs +76 -10
- package/fesm2022/rt-tools-ui-kit-v2-aside.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-button.mjs +18 -9
- package/fesm2022/rt-tools-ui-kit-v2-button.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-confirm-popover.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-confirm-popover.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs +66 -4
- package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-markdown-text.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-markdown-text.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +128 -20
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs +2 -2
- package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-usage-ring.mjs +163 -0
- package/fesm2022/rt-tools-ui-kit-v2-usage-ring.mjs.map +1 -0
- package/fesm2022/rt-tools-ui-kit-v2.mjs +2 -0
- package/package.json +9 -1
- package/src/lib/components/ai-prompt-input/CONTEXT.md +60 -0
- package/src/lib/components/ai-prompt-input/rt-ai-prompt-input.component.scss +113 -0
- package/src/lib/components/aside/footer/rt-aside-footer.component.scss +3 -1
- package/src/lib/components/aside/unsaved-dialog/rt-aside-unsaved-dialog.component.scss +10 -3
- package/src/lib/components/markdown-text/rt-markdown-text.component.scss +3 -0
- package/src/lib/components/thread-list/rt-thread-list.component.scss +19 -11
- package/src/lib/components/usage-ring/CONTEXT.md +33 -0
- package/src/lib/components/usage-ring/rt-usage-ring.component.scss +64 -0
- package/src/rich-editor/lib/components/ai-chat/CONTEXT.md +1 -1
- package/src/rich-editor/lib/components/ai-chat/answer/rt-ai-chat-answer.component.scss +1 -0
- package/src/rich-editor/lib/components/ai-chat/rt-ai-chat.component.scss +6 -0
- package/types/rt-tools-ui-kit-v2-ai-prompt-input.d.ts +193 -0
- package/types/rt-tools-ui-kit-v2-aside.d.ts +17 -7
- package/types/rt-tools-ui-kit-v2-button.d.ts +6 -1
- package/types/rt-tools-ui-kit-v2-core.d.ts +22 -0
- package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +49 -3
- package/types/rt-tools-ui-kit-v2-usage-ring.d.ts +47 -0
- package/types/rt-tools-ui-kit-v2.d.ts +2 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rt-tools-ui-kit-v2-button.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/button/rt-button.directive.ts"],"sourcesContent":["import { FocusMonitor } from '@angular/cdk/a11y';\nimport { BooleanInput } from '@angular/cdk/coercion';\nimport { DOCUMENT } from '@angular/common';\nimport {\n afterNextRender,\n booleanAttribute,\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n HostBinding,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n Renderer2,\n Signal,\n untracked,\n} from '@angular/core';\n\nimport { IRtKitConfig } from '@rt-tools/ui-kit-v2/core';\nimport { rtKitDefault } from '@rt-tools/ui-kit-v2/core';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RT_RADIUS_DEFAULT, TRtRadius } from '@rt-tools/ui-kit-v2/core';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport {\n RT_ICON_GLYPH_STRATEGY,\n RT_ICON_MATERIAL_PRESET_SELECTOR,\n RtIconFontService,\n RtIconRegistry,\n resolveIconGlyph,\n} from '@rt-tools/ui-kit-v2/icon';\nimport { iconMaterialDrawn } from '@rt-tools/ui-kit-v2/icon';\nimport { RtRippleDirective } from '@rt-tools/ui-kit-v2/ripple';\nimport { IButton } from '@rt-tools/ui-kit-v2/core';\n\nconst BEM_BLOCK: string = 'rt-button';\n\n/** Длительность затухания спиннера при выходе из загрузки. */\nconst LOADING_FADE_OUT_MS: number = 300;\n\n/** Запас поверх затухания, после которого подпись возвращается без анимации. */\nconst LOADING_FADE_OUT_BUFFER_MS: number = 50;\n\n/**\n * Директива стилизованной кнопки. Применяется к `<button>` или `<a>`\n * (для ссылок-кнопок с `routerLink`/`href`).\n *\n * Иконка и лейбл рендерятся внутрь элемента через `Renderer2`, чтобы можно\n * было применять директиву к существующему элементу без обёртки.\n * Поддерживает анимированный переход в/из loading.\n *\n * @example\n * ```html\n * <button rtButton label=\"Войти\" theme=\"primary\"></button>\n * <button rtButton label=\"Скачать\" icon=\"ico-download\" theme=\"success\"></button>\n * <button rtButton icon=\"pencil\" theme=\"info\" appearance=\"text\"></button>\n * <button rtButton label=\"Сохранение...\" [loading]=\"saving()\" [disabled]=\"saving()\"></button>\n * <a rtButton label=\"Главная\" [routerLink]=\"'/'\"></a>\n * ```\n */\n@Directive({\n selector: 'button[rtButton], a[rtButton]',\n hostDirectives: [\n { directive: RtRippleDirective, inputs: ['rippleDisabled'] },\n { directive: RtRadiusDirective, inputs: ['radius'] },\n ],\n /* Шаг скругления без входа берётся из настроек кита: приложение, скруглившее все кнопки разом,\n называет шаг один раз, а вход на кнопке по-прежнему сильнее. */\n providers: [\n {\n provide: RT_RADIUS_DEFAULT,\n useFactory: (): TRtRadius | null =>\n rtKitDefault('button', (it: IRtKitConfig.Button): TRtRadius | null | undefined => it.radius, null),\n },\n ],\n})\nexport class RtButtonDirective {\n readonly #el: ElementRef<HTMLButtonElement | HTMLAnchorElement> = inject<ElementRef<HTMLButtonElement | HTMLAnchorElement>>(ElementRef);\n readonly #renderer: Renderer2 = inject(Renderer2);\n readonly #focusMonitor: FocusMonitor = inject(FocusMonitor);\n readonly #doc: Document = inject(DOCUMENT);\n readonly #iconRegistry: RtIconRegistry = inject(RtIconRegistry);\n readonly #glyphStrategy: IRtIcon.GlyphStrategy = inject(RT_ICON_GLYPH_STRATEGY);\n readonly #fontReady: Signal<boolean> = inject(RtIconFontService).ready;\n\n /* С чего стартуют три входа, которые приложение вправе задать киту разом. Значение считается\n из настроек при объявлении входа: так публичный вид входа не меняется — ни тип, ни имя, — а\n вход, написанный в разметке, по-прежнему перебивает всё. Цена — настройки читаются один раз,\n когда узел создан. */\n readonly #appearance: IButton.Appearance = rtKitDefault(\n 'button',\n (it: IRtKitConfig.Button): IButton.Appearance | undefined => it.appearance,\n 'filled'\n );\n readonly #size: IButton.Size = rtKitDefault('button', (it: IRtKitConfig.Button): IButton.Size | undefined => it.size, 'md');\n\n #iconEl: HTMLElement | null = null;\n #labelEl: HTMLElement | null = null;\n #spinnerEl: HTMLElement | null = null;\n #wasLoading: boolean = false;\n\n protected readonly isIconOnly: Signal<boolean> = computed(() => !!this.icon() && !this.label());\n\n /** Текстовый лейбл кнопки. Если null — кнопка только с иконкой. */\n public readonly label: InputSignal<string | null> = input<string | null>(null);\n /**\n * Значок кнопки: имя кита (`check`) или имя Material (`arrow_back`). Имя Material рисуется\n * так же, как вход `glyph` у `rt-icon`: парой из перечня кита или лигатурой шрифта — по\n * настройке `glyphStrategy` у `provideRtIcons()`. Если null — без иконки.\n */\n public readonly icon: InputSignal<string | null> = input<string | null>(null);\n /** Сторона размещения иконки относительно лейбла. */\n public readonly iconPos: InputSignal<IButton.IconPos> = input<IButton.IconPos>('left');\n /** Семантическая палитра. */\n public readonly theme: InputSignal<IButton.Theme> = input<IButton.Theme>('primary');\n /** Внешний вид (filled / outlined / text). Умолчание — из настроек кита. */\n public readonly appearance: InputSignal<IButton.Appearance> = input<IButton.Appearance>(this.#appearance);\n /** Размер. Умолчание — из настроек кита. */\n public readonly size: InputSignal<IButton.Size> = input<IButton.Size>(this.#size);\n /** Состояние загрузки: показывает спиннер вместо иконки, блокирует клики. */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Кастомный CSS-класс иконки в loading. Если null — встроенный CSS-спиннер. */\n public readonly loadingIcon: InputSignal<string | null> = input<string | null>(null);\n /**\n * Подпись во время загрузки. `hide` оставляет подпись и иконку в кнопке невидимыми — ширина\n * не скачет, — а спиннер ставит по центру; имя кнопки для скринридера остаётся.\n */\n public readonly loadingLabel: InputSignal<IButton.LoadingLabel> = input<IButton.LoadingLabel>('keep');\n\n /**\n * Положение двухпозиционной кнопки: `true` — нажата, `false` — отжата, `null` — положения нет\n * вовсе.\n *\n * Три значения, а не два, потому что обычная кнопка переключателем не является и объявлять\n * себя двухпозиционной не должна: сказанное вспомогательным средствам «эта кнопка отжата» на\n * кнопке, которая просто запускает действие, — ложь, а не умолчание. Отжатое положение при\n * этом объявляется наравне с нажатым: молчащая в отжатом виде кнопка неотличима от обычной, и\n * о втором положении узнают только нажав.\n *\n * Само по нажатию положение не меняется: кнопка говорит о нажатии наружу, а положение\n * возвращает вызывающий — иначе вид кнопки и состояние приложения расходятся при первом же\n * отказе сохранения.\n */\n public readonly pressed: InputSignal<boolean | null> = input<boolean | null>(null);\n\n constructor() {\n afterNextRender(() => untracked(() => this.#updateContent()));\n\n /* Источник фокуса пишет CDK классами `cdk-keyboard-focused`, `cdk-mouse-focused` и\n соседними, как у Material: кольцо фокуса рисуется только не от мыши и не от касания.\n Сам монитор, а не `CdkMonitorFocus` хозяином: приложение вправе поставить на ту же\n кнопку `cdkMonitorElementFocus`, и директива дважды на узле — ошибка NG0309. */\n this.#focusMonitor.monitor(this.#el);\n inject(DestroyRef).onDestroy((): void => this.#focusMonitor.stopMonitoring(this.#el));\n\n effect(() => {\n this.label();\n this.icon();\n this.iconPos();\n this.loading();\n this.loadingIcon();\n this.loadingLabel();\n // Лигатура до готовности шрифтов скрыта: готовность перерисовывает содержимое.\n this.#fontReady();\n\n untracked(() => this.#updateContent());\n });\n }\n\n /** Положение наружу: атрибута нет вовсе там, где положения у кнопки не бывает. */\n @HostBinding('attr.aria-pressed')\n protected get ariaPressed(): string | null {\n const pressed: boolean | null = this.pressed();\n\n return pressed === null ? null : String(pressed);\n }\n\n @HostBinding('class')\n protected get hostClasses(): Record<string, boolean> {\n const theme: IButton.Theme = this.theme();\n const appearance: IButton.Appearance = this.appearance();\n const size: IButton.Size = this.size();\n\n return {\n [BEM_BLOCK]: true,\n [`${BEM_BLOCK}--${theme}`]: theme !== 'primary',\n [`${BEM_BLOCK}--outlined`]: appearance === 'outlined',\n [`${BEM_BLOCK}--text`]: appearance === 'text',\n [`${BEM_BLOCK}--loading`]: this.loading(),\n [`${BEM_BLOCK}--loading-label-hidden`]: this.loading() && this.loadingLabel() === 'hide',\n [`${BEM_BLOCK}--icon-only`]: this.isIconOnly(),\n [`${BEM_BLOCK}--${size}`]: size !== 'md',\n [`${BEM_BLOCK}--pressed`]: this.pressed() === true,\n };\n }\n\n #updateContent(): void {\n const button: HTMLButtonElement | HTMLAnchorElement = this.#el.nativeElement;\n const isLoading: boolean = this.loading();\n const wasLoading: boolean = this.#wasLoading;\n this.#wasLoading = isLoading;\n\n if (wasLoading && !isLoading) {\n this.#transitionFromLoading(button);\n return;\n }\n\n this.#clearContent(button);\n\n if (isLoading) {\n this.#renderLoading(button);\n return;\n }\n\n this.#renderIconAndLabel(button);\n }\n\n #transitionFromLoading(button: HTMLElement): void {\n const spinnerEl: HTMLElement | null = this.#spinnerEl;\n\n if (spinnerEl === null) {\n this.#restoreContent(button);\n return;\n }\n\n spinnerEl.style.animation = `rt-button-fade-out ${LOADING_FADE_OUT_MS}ms ease-out forwards`;\n\n // settled-гард делает animationend и страховочный таймаут взаимно\n // идемпотентными — сработает и снимет listener только то, что раньше.\n // Без таймаута подпись возвращалась бы только по анимации, а она не\n // идёт, пока кнопка спрятана (свёрнутая панель, неактивная вкладка):\n // выход из загрузки не наступал никогда, и на кнопке навсегда\n // оставался голый спиннер.\n let settled: boolean = false;\n\n const finish: () => void = (): void => {\n if (settled) {\n return;\n }\n settled = true;\n spinnerEl.removeEventListener('animationend', finish);\n this.#restoreContent(button);\n };\n\n spinnerEl.addEventListener('animationend', finish);\n setTimeout(finish, LOADING_FADE_OUT_MS + LOADING_FADE_OUT_BUFFER_MS);\n }\n\n #restoreContent(button: HTMLElement): void {\n this.#clearContent(button);\n this.#renderIconAndLabel(button);\n }\n\n /**\n * Чистим по классу, а не по своим ссылкам. Под серверным рендером разметку\n * кнопки рисует сервер: после гидратации лейбл и иконка уже лежат в DOM, но создавал их\n * другой экземпляр директивы, и `#labelEl` у клиентского — пустой. Ссылки\n * тогда не находят ничего, а `#renderIconAndLabel` дорисовывает второй\n * лейбл — подпись кнопки удваивается («СохранитьСохранить»).\n */\n #clearContent(button: HTMLElement): void {\n const ownClasses: ReadonlyArray<string> = [`${BEM_BLOCK}__icon`, `${BEM_BLOCK}__label`, `${BEM_BLOCK}__spinner`];\n\n // Обход по детям, а не селектором `:scope >`: тот же код исполняется на\n // сервере, где DOM эмулированный и селекторный движок урезан\n for (const child of Array.from(button.children)) {\n if (ownClasses.some((ownClass: string): boolean => child.classList.contains(ownClass))) {\n this.#renderer.removeChild(button, child);\n }\n }\n\n this.#iconEl = null;\n this.#labelEl = null;\n this.#spinnerEl = null;\n }\n\n #renderLoading(button: HTMLElement): void {\n const loadingIcon: string | null = this.loadingIcon();\n const loader: HTMLElement = loadingIcon ? this.#createIcon(loadingIcon) : this.#createSpinner();\n\n if (this.loadingLabel() === 'hide') {\n // Обычное содержимое остаётся и держит ширину; стили гасят его и ставят\n // загрузчик поверх по центру\n this.#renderIconAndLabel(button);\n this.#renderer.addClass(loader, `${BEM_BLOCK}__loader`);\n this.#renderer.appendChild(button, loader);\n if (!loadingIcon) {\n this.#spinnerEl = loader;\n }\n return;\n }\n\n if (loadingIcon) {\n this.#iconEl = loader;\n this.#renderer.appendChild(button, this.#iconEl);\n } else {\n this.#spinnerEl = loader;\n this.#renderer.appendChild(button, this.#spinnerEl);\n }\n\n const label: string | null = this.label();\n if (label) {\n this.#labelEl = this.#createLabel(label);\n this.#renderer.appendChild(button, this.#labelEl);\n }\n }\n\n #renderIconAndLabel(button: HTMLElement): void {\n const iconClass: string | null = this.icon();\n const label: string | null = this.label();\n const pos: IButton.IconPos = this.iconPos();\n\n const iconEl: HTMLElement | null = iconClass ? this.#createIcon(iconClass) : null;\n const labelEl: HTMLElement | null = label ? this.#createLabel(label) : null;\n\n if (pos === 'left') {\n if (iconEl) {\n this.#renderer.appendChild(button, iconEl);\n }\n if (labelEl) {\n this.#renderer.appendChild(button, labelEl);\n }\n } else {\n if (labelEl) {\n this.#renderer.appendChild(button, labelEl);\n }\n if (iconEl) {\n this.#renderer.appendChild(button, iconEl);\n }\n }\n\n this.#iconEl = iconEl;\n this.#labelEl = labelEl;\n }\n\n #createIcon(iconName: string): HTMLElement {\n const resolved: IRtIcon.Resolved | null = resolveIconGlyph(null, iconName, this.#glyphStrategy);\n if (resolved?.kind === 'kit') {\n return this.#createKitIcon(resolved.name);\n }\n return this.#createGlyph(iconName);\n }\n\n #createKitIcon(name: IRtIcon.Name): HTMLElement {\n const svg: SVGSVGElement = this.#doc.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('focusable', 'false');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.classList.add(`${BEM_BLOCK}__icon`);\n\n // Тот же путь, что и у компонента значка: имя просится у реестра, а он ходит за файлом\n // один раз на страницу — значок, спрошенный обеими разметками сразу, едет одним запросом.\n const drawing: IRtIcon.Drawing = this.#drawingOf(name);\n this.#iconRegistry.request(name, drawing);\n\n const use: SVGUseElement = this.#doc.createElementNS('http://www.w3.org/2000/svg', 'use');\n use.setAttribute('href', this.#iconRegistry.symbolHref(name, drawing));\n svg.appendChild(use);\n\n return svg as unknown as HTMLElement;\n }\n\n /**\n * Набор рисунка — как у компонента значка: материальный рисунок под разметкой с признаком\n * материального набора, если у имени он есть. Признак читается при каждой отрисовке\n * содержимого, а после первой отрисовки она повторяется — контейнер к тому времени на месте.\n */\n #drawingOf(name: IRtIcon.Name): IRtIcon.Drawing {\n const underMaterial: boolean = this.#el.nativeElement.closest(RT_ICON_MATERIAL_PRESET_SELECTOR) !== null;\n return underMaterial && iconMaterialDrawn.has(name) ? 'material' : 'base';\n }\n\n /** Лигатура шрифта Material Symbols для имени без пары. Шрифт подключает приложение. */\n #createGlyph(glyph: string): HTMLElement {\n const el: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(el, `${BEM_BLOCK}__icon`);\n this.#renderer.addClass(el, `${BEM_BLOCK}__glyph`);\n if (!this.#fontReady()) {\n this.#renderer.addClass(el, `${BEM_BLOCK}__glyph--pending`);\n }\n this.#renderer.setAttribute(el, 'aria-hidden', 'true');\n this.#renderer.appendChild(el, this.#renderer.createText(glyph));\n return el;\n }\n\n #createLabel(text: string): HTMLElement {\n const el: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(el, `${BEM_BLOCK}__label`);\n this.#renderer.appendChild(el, this.#renderer.createText(text));\n return el;\n }\n\n #createSpinner(): HTMLElement {\n const wrapper: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(wrapper, `${BEM_BLOCK}__spinner`);\n\n const circle: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(circle, `${BEM_BLOCK}__spinner-circle`);\n this.#renderer.appendChild(wrapper, circle);\n\n return wrapper;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rt-tools-ui-kit-v2-button.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/button/rt-button.directive.ts"],"sourcesContent":["import { FocusMonitor } from '@angular/cdk/a11y';\nimport { BooleanInput } from '@angular/cdk/coercion';\nimport { DOCUMENT } from '@angular/common';\nimport {\n afterNextRender,\n booleanAttribute,\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n HostBinding,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n Renderer2,\n signal,\n Signal,\n untracked,\n WritableSignal,\n} from '@angular/core';\n\nimport { IRtKitConfig } from '@rt-tools/ui-kit-v2/core';\nimport { rtKitDefault } from '@rt-tools/ui-kit-v2/core';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RT_RADIUS_DEFAULT, TRtRadius } from '@rt-tools/ui-kit-v2/core';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport {\n RT_ICON_GLYPH_STRATEGY,\n RT_ICON_MATERIAL_PRESET_SELECTOR,\n RtIconFontService,\n RtIconRegistry,\n resolveIconGlyph,\n} from '@rt-tools/ui-kit-v2/icon';\nimport { iconMaterialDrawn } from '@rt-tools/ui-kit-v2/icon';\nimport { RtRippleDirective } from '@rt-tools/ui-kit-v2/ripple';\nimport { IButton } from '@rt-tools/ui-kit-v2/core';\n\nconst BEM_BLOCK: string = 'rt-button';\n\n/** Длительность затухания спиннера при выходе из загрузки. */\nconst LOADING_FADE_OUT_MS: number = 300;\n\n/** Запас поверх затухания, после которого подпись возвращается без анимации. */\nconst LOADING_FADE_OUT_BUFFER_MS: number = 50;\n\n/**\n * Директива стилизованной кнопки. Применяется к `<button>` или `<a>`\n * (для ссылок-кнопок с `routerLink`/`href`).\n *\n * Иконка и лейбл рендерятся внутрь элемента через `Renderer2`, чтобы можно\n * было применять директиву к существующему элементу без обёртки.\n * Поддерживает анимированный переход в/из loading.\n *\n * @example\n * ```html\n * <button rtButton label=\"Войти\" theme=\"primary\"></button>\n * <button rtButton label=\"Скачать\" icon=\"ico-download\" theme=\"success\"></button>\n * <button rtButton icon=\"pencil\" theme=\"info\" appearance=\"text\"></button>\n * <button rtButton label=\"Сохранение...\" [loading]=\"saving()\" [disabled]=\"saving()\"></button>\n * <a rtButton label=\"Главная\" [routerLink]=\"'/'\"></a>\n * ```\n */\n@Directive({\n selector: 'button[rtButton], a[rtButton]',\n hostDirectives: [\n { directive: RtRippleDirective, inputs: ['rippleDisabled'] },\n { directive: RtRadiusDirective, inputs: ['radius'] },\n ],\n /* Шаг скругления без входа берётся из настроек кита: приложение, скруглившее все кнопки разом,\n называет шаг один раз, а вход на кнопке по-прежнему сильнее. */\n providers: [\n {\n provide: RT_RADIUS_DEFAULT,\n useFactory: (): TRtRadius | null =>\n rtKitDefault('button', (it: IRtKitConfig.Button): TRtRadius | null | undefined => it.radius, null),\n },\n ],\n})\nexport class RtButtonDirective {\n readonly #el: ElementRef<HTMLButtonElement | HTMLAnchorElement> = inject<ElementRef<HTMLButtonElement | HTMLAnchorElement>>(ElementRef);\n readonly #renderer: Renderer2 = inject(Renderer2);\n readonly #focusMonitor: FocusMonitor = inject(FocusMonitor);\n readonly #doc: Document = inject(DOCUMENT);\n readonly #iconRegistry: RtIconRegistry = inject(RtIconRegistry);\n readonly #glyphStrategy: IRtIcon.GlyphStrategy = inject(RT_ICON_GLYPH_STRATEGY);\n readonly #fontReady: Signal<boolean> = inject(RtIconFontService).ready;\n\n /* С чего стартуют три входа, которые приложение вправе задать киту разом. Значение считается\n из настроек при объявлении входа: так публичный вид входа не меняется — ни тип, ни имя, — а\n вход, написанный в разметке, по-прежнему перебивает всё. Цена — настройки читаются один раз,\n когда узел создан. */\n readonly #appearance: IButton.Appearance = rtKitDefault(\n 'button',\n (it: IRtKitConfig.Button): IButton.Appearance | undefined => it.appearance,\n 'filled'\n );\n readonly #size: IButton.Size = rtKitDefault('button', (it: IRtKitConfig.Button): IButton.Size | undefined => it.size, 'md');\n\n #iconEl: HTMLElement | null = null;\n #labelEl: HTMLElement | null = null;\n #spinnerEl: HTMLElement | null = null;\n #wasLoading: boolean = false;\n\n readonly #theme: Signal<IButton.Theme> = computed(() => this.placeLook()?.theme ?? this.theme());\n readonly #appearanceShown: Signal<IButton.Appearance> = computed(() => this.placeLook()?.appearance ?? this.appearance());\n readonly #icon: Signal<string | null> = computed(() => (this.placeLook()?.icon === null ? null : this.icon()));\n readonly #label: Signal<string | null> = computed(() => this.placeLook()?.label ?? this.label());\n\n protected readonly isIconOnly: Signal<boolean> = computed(() => !!this.#icon() && !this.#label());\n\n /**\n * Вид, который задаёт место кнопки: слот подвала панели. Пишет его хозяин места, а не\n * приложение, — входы кнопки при этом не трогаются и вернутся, когда место вид снимет.\n */\n public readonly placeLook: WritableSignal<IButton.PlaceLook | null> = signal<IButton.PlaceLook | null>(null);\n\n /** Текстовый лейбл кнопки. Если null — кнопка только с иконкой. */\n public readonly label: InputSignal<string | null> = input<string | null>(null);\n /**\n * Значок кнопки: имя кита (`check`) или имя Material (`arrow_back`). Имя Material рисуется\n * так же, как вход `glyph` у `rt-icon`: парой из перечня кита или лигатурой шрифта — по\n * настройке `glyphStrategy` у `provideRtIcons()`. Если null — без иконки.\n */\n public readonly icon: InputSignal<string | null> = input<string | null>(null);\n /** Сторона размещения иконки относительно лейбла. */\n public readonly iconPos: InputSignal<IButton.IconPos> = input<IButton.IconPos>('left');\n /** Семантическая палитра. */\n public readonly theme: InputSignal<IButton.Theme> = input<IButton.Theme>('primary');\n /** Внешний вид (filled / outlined / text). Умолчание — из настроек кита. */\n public readonly appearance: InputSignal<IButton.Appearance> = input<IButton.Appearance>(this.#appearance);\n /** Размер. Умолчание — из настроек кита. */\n public readonly size: InputSignal<IButton.Size> = input<IButton.Size>(this.#size);\n /** Состояние загрузки: показывает спиннер вместо иконки, блокирует клики. */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Кастомный CSS-класс иконки в loading. Если null — встроенный CSS-спиннер. */\n public readonly loadingIcon: InputSignal<string | null> = input<string | null>(null);\n /**\n * Подпись во время загрузки. `hide` оставляет подпись и иконку в кнопке невидимыми — ширина\n * не скачет, — а спиннер ставит по центру; имя кнопки для скринридера остаётся.\n */\n public readonly loadingLabel: InputSignal<IButton.LoadingLabel> = input<IButton.LoadingLabel>('keep');\n\n /**\n * Положение двухпозиционной кнопки: `true` — нажата, `false` — отжата, `null` — положения нет\n * вовсе.\n *\n * Три значения, а не два, потому что обычная кнопка переключателем не является и объявлять\n * себя двухпозиционной не должна: сказанное вспомогательным средствам «эта кнопка отжата» на\n * кнопке, которая просто запускает действие, — ложь, а не умолчание. Отжатое положение при\n * этом объявляется наравне с нажатым: молчащая в отжатом виде кнопка неотличима от обычной, и\n * о втором положении узнают только нажав.\n *\n * Само по нажатию положение не меняется: кнопка говорит о нажатии наружу, а положение\n * возвращает вызывающий — иначе вид кнопки и состояние приложения расходятся при первом же\n * отказе сохранения.\n */\n public readonly pressed: InputSignal<boolean | null> = input<boolean | null>(null);\n\n constructor() {\n afterNextRender(() => untracked(() => this.#updateContent()));\n\n /* Источник фокуса пишет CDK классами `cdk-keyboard-focused`, `cdk-mouse-focused` и\n соседними, как у Material: кольцо фокуса рисуется только не от мыши и не от касания.\n Сам монитор, а не `CdkMonitorFocus` хозяином: приложение вправе поставить на ту же\n кнопку `cdkMonitorElementFocus`, и директива дважды на узле — ошибка NG0309. */\n this.#focusMonitor.monitor(this.#el);\n inject(DestroyRef).onDestroy((): void => this.#focusMonitor.stopMonitoring(this.#el));\n\n effect(() => {\n this.#label();\n this.#icon();\n this.iconPos();\n this.loading();\n this.loadingIcon();\n this.loadingLabel();\n // Лигатура до готовности шрифтов скрыта: готовность перерисовывает содержимое.\n this.#fontReady();\n\n untracked(() => this.#updateContent());\n });\n }\n\n /** Положение наружу: атрибута нет вовсе там, где положения у кнопки не бывает. */\n @HostBinding('attr.aria-pressed')\n protected get ariaPressed(): string | null {\n const pressed: boolean | null = this.pressed();\n\n return pressed === null ? null : String(pressed);\n }\n\n @HostBinding('class')\n protected get hostClasses(): Record<string, boolean> {\n const theme: IButton.Theme = this.#theme();\n const appearance: IButton.Appearance = this.#appearanceShown();\n const size: IButton.Size = this.size();\n\n return {\n [BEM_BLOCK]: true,\n [`${BEM_BLOCK}--${theme}`]: theme !== 'primary',\n [`${BEM_BLOCK}--outlined`]: appearance === 'outlined',\n [`${BEM_BLOCK}--text`]: appearance === 'text',\n [`${BEM_BLOCK}--loading`]: this.loading(),\n [`${BEM_BLOCK}--loading-label-hidden`]: this.loading() && this.loadingLabel() === 'hide',\n [`${BEM_BLOCK}--icon-only`]: this.isIconOnly(),\n [`${BEM_BLOCK}--${size}`]: size !== 'md',\n [`${BEM_BLOCK}--pressed`]: this.pressed() === true,\n };\n }\n\n #updateContent(): void {\n const button: HTMLButtonElement | HTMLAnchorElement = this.#el.nativeElement;\n const isLoading: boolean = this.loading();\n const wasLoading: boolean = this.#wasLoading;\n this.#wasLoading = isLoading;\n\n if (wasLoading && !isLoading) {\n this.#transitionFromLoading(button);\n return;\n }\n\n this.#clearContent(button);\n\n if (isLoading) {\n this.#renderLoading(button);\n return;\n }\n\n this.#renderIconAndLabel(button);\n }\n\n #transitionFromLoading(button: HTMLElement): void {\n const spinnerEl: HTMLElement | null = this.#spinnerEl;\n\n if (spinnerEl === null) {\n this.#restoreContent(button);\n return;\n }\n\n spinnerEl.style.animation = `rt-button-fade-out ${LOADING_FADE_OUT_MS}ms ease-out forwards`;\n\n // settled-гард делает animationend и страховочный таймаут взаимно\n // идемпотентными — сработает и снимет listener только то, что раньше.\n // Без таймаута подпись возвращалась бы только по анимации, а она не\n // идёт, пока кнопка спрятана (свёрнутая панель, неактивная вкладка):\n // выход из загрузки не наступал никогда, и на кнопке навсегда\n // оставался голый спиннер.\n let settled: boolean = false;\n\n const finish: () => void = (): void => {\n if (settled) {\n return;\n }\n settled = true;\n spinnerEl.removeEventListener('animationend', finish);\n this.#restoreContent(button);\n };\n\n spinnerEl.addEventListener('animationend', finish);\n setTimeout(finish, LOADING_FADE_OUT_MS + LOADING_FADE_OUT_BUFFER_MS);\n }\n\n #restoreContent(button: HTMLElement): void {\n this.#clearContent(button);\n this.#renderIconAndLabel(button);\n }\n\n /**\n * Чистим по классу, а не по своим ссылкам. Под серверным рендером разметку\n * кнопки рисует сервер: после гидратации лейбл и иконка уже лежат в DOM, но создавал их\n * другой экземпляр директивы, и `#labelEl` у клиентского — пустой. Ссылки\n * тогда не находят ничего, а `#renderIconAndLabel` дорисовывает второй\n * лейбл — подпись кнопки удваивается («СохранитьСохранить»).\n */\n #clearContent(button: HTMLElement): void {\n const ownClasses: ReadonlyArray<string> = [`${BEM_BLOCK}__icon`, `${BEM_BLOCK}__label`, `${BEM_BLOCK}__spinner`];\n\n // Обход по детям, а не селектором `:scope >`: тот же код исполняется на\n // сервере, где DOM эмулированный и селекторный движок урезан\n for (const child of Array.from(button.children)) {\n if (ownClasses.some((ownClass: string): boolean => child.classList.contains(ownClass))) {\n this.#renderer.removeChild(button, child);\n }\n }\n\n this.#iconEl = null;\n this.#labelEl = null;\n this.#spinnerEl = null;\n }\n\n #renderLoading(button: HTMLElement): void {\n const loadingIcon: string | null = this.loadingIcon();\n const loader: HTMLElement = loadingIcon ? this.#createIcon(loadingIcon) : this.#createSpinner();\n\n if (this.loadingLabel() === 'hide') {\n // Обычное содержимое остаётся и держит ширину; стили гасят его и ставят\n // загрузчик поверх по центру\n this.#renderIconAndLabel(button);\n this.#renderer.addClass(loader, `${BEM_BLOCK}__loader`);\n this.#renderer.appendChild(button, loader);\n if (!loadingIcon) {\n this.#spinnerEl = loader;\n }\n return;\n }\n\n if (loadingIcon) {\n this.#iconEl = loader;\n this.#renderer.appendChild(button, this.#iconEl);\n } else {\n this.#spinnerEl = loader;\n this.#renderer.appendChild(button, this.#spinnerEl);\n }\n\n const label: string | null = this.#label();\n if (label) {\n this.#labelEl = this.#createLabel(label);\n this.#renderer.appendChild(button, this.#labelEl);\n }\n }\n\n #renderIconAndLabel(button: HTMLElement): void {\n const iconClass: string | null = this.#icon();\n const label: string | null = this.#label();\n const pos: IButton.IconPos = this.iconPos();\n\n const iconEl: HTMLElement | null = iconClass ? this.#createIcon(iconClass) : null;\n const labelEl: HTMLElement | null = label ? this.#createLabel(label) : null;\n\n if (pos === 'left') {\n if (iconEl) {\n this.#renderer.appendChild(button, iconEl);\n }\n if (labelEl) {\n this.#renderer.appendChild(button, labelEl);\n }\n } else {\n if (labelEl) {\n this.#renderer.appendChild(button, labelEl);\n }\n if (iconEl) {\n this.#renderer.appendChild(button, iconEl);\n }\n }\n\n this.#iconEl = iconEl;\n this.#labelEl = labelEl;\n }\n\n #createIcon(iconName: string): HTMLElement {\n const resolved: IRtIcon.Resolved | null = resolveIconGlyph(null, iconName, this.#glyphStrategy);\n if (resolved?.kind === 'kit') {\n return this.#createKitIcon(resolved.name);\n }\n return this.#createGlyph(iconName);\n }\n\n #createKitIcon(name: IRtIcon.Name): HTMLElement {\n const svg: SVGSVGElement = this.#doc.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('focusable', 'false');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.classList.add(`${BEM_BLOCK}__icon`);\n\n // Тот же путь, что и у компонента значка: имя просится у реестра, а он ходит за файлом\n // один раз на страницу — значок, спрошенный обеими разметками сразу, едет одним запросом.\n const drawing: IRtIcon.Drawing = this.#drawingOf(name);\n this.#iconRegistry.request(name, drawing);\n\n const use: SVGUseElement = this.#doc.createElementNS('http://www.w3.org/2000/svg', 'use');\n use.setAttribute('href', this.#iconRegistry.symbolHref(name, drawing));\n svg.appendChild(use);\n\n return svg as unknown as HTMLElement;\n }\n\n /**\n * Набор рисунка — как у компонента значка: материальный рисунок под разметкой с признаком\n * материального набора, если у имени он есть. Признак читается при каждой отрисовке\n * содержимого, а после первой отрисовки она повторяется — контейнер к тому времени на месте.\n */\n #drawingOf(name: IRtIcon.Name): IRtIcon.Drawing {\n const underMaterial: boolean = this.#el.nativeElement.closest(RT_ICON_MATERIAL_PRESET_SELECTOR) !== null;\n return underMaterial && iconMaterialDrawn.has(name) ? 'material' : 'base';\n }\n\n /** Лигатура шрифта Material Symbols для имени без пары. Шрифт подключает приложение. */\n #createGlyph(glyph: string): HTMLElement {\n const el: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(el, `${BEM_BLOCK}__icon`);\n this.#renderer.addClass(el, `${BEM_BLOCK}__glyph`);\n if (!this.#fontReady()) {\n this.#renderer.addClass(el, `${BEM_BLOCK}__glyph--pending`);\n }\n this.#renderer.setAttribute(el, 'aria-hidden', 'true');\n this.#renderer.appendChild(el, this.#renderer.createText(glyph));\n return el;\n }\n\n #createLabel(text: string): HTMLElement {\n const el: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(el, `${BEM_BLOCK}__label`);\n this.#renderer.appendChild(el, this.#renderer.createText(text));\n return el;\n }\n\n #createSpinner(): HTMLElement {\n const wrapper: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(wrapper, `${BEM_BLOCK}__spinner`);\n\n const circle: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(circle, `${BEM_BLOCK}__spinner-circle`);\n this.#renderer.appendChild(wrapper, circle);\n\n return wrapper;\n }\n}\n"],"mappings":";;;;;;;;;;AAuCA,MAAM,YAAoB;AAG1B,MAAM,sBAA8B;AAsCpC,IAAa,oBAAb,MAAa,kBAAiB;CACjB;CACA;CACA;CACA;CACA;CACA;CACA;CAMA;CAKA;CAET;CACA;CACA;CACA;CAES;CACA;CACA;CACA;CAsDT,cAAA;EAjFS,KAAA,MAAyD,OAA0D,UAAU;EAC7H,KAAA,YAAuB,OAAO,SAAS;EACvC,KAAA,gBAA8B,OAAO,YAAY;EACjD,KAAA,OAAiB,OAAO,QAAQ;EAChC,KAAA,gBAAgC,OAAO,cAAc;EACrD,KAAA,iBAAwC,OAAO,sBAAsB;EACrE,KAAA,aAA8B,OAAO,iBAAiB,CAAC,CAAC;EAMxD,KAAA,cAAkC,aACvC,WACC,OAA4D,GAAG,YAChE,QAAQ;EAEH,KAAA,QAAsB,aAAa,WAAW,OAAsD,GAAG,MAAM,IAAI;EAE1H,KAAA,UAA8B;EAC9B,KAAA,WAA+B;EAC/B,KAAA,aAAiC;EACjC,KAAA,cAAuB;EAEd,KAAA,SAAgC,eAAe,KAAK,UAAS,CAAE,EAAE,SAAS,KAAK,MAAK,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EACvF,KAAA,mBAA+C,eAAe,KAAK,UAAS,CAAE,EAAE,cAAc,KAAK,WAAU,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,mBAAA,CAAA,+BAAA,CAAA,CAAA;EAChH,KAAA,QAA+B,eAAgB,KAAK,UAAS,CAAE,EAAE,SAAS,OAAO,OAAO,KAAK,KAAI,GAAI,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EACrG,KAAA,SAAgC,eAAe,KAAK,UAAS,CAAE,EAAE,SAAS,KAAK,MAAK,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EAE7E,KAAA,aAA8B,eAAe,CAAC,CAAC,KAAK,MAAK,KAAM,CAAC,KAAK,OAAM,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;EAMjF,KAAA,YAAsD,OAAiC,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;EAG5F,KAAA,QAAoC,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EAM9D,KAAA,OAAmC,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;EAE7D,KAAA,UAAwC,MAAuB,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;EAEtE,KAAA,QAAoC,MAAqB,WAAU,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EAEnE,KAAA,aAA8C,MAA0B,KAAK,aAAY,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;EAEzF,KAAA,OAAkC,MAAoB,KAAK,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;EAEjE,KAAA,UAA2D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,UAAA,+BAAA,CAAA;GACzG,WAAW;EAAgB,CAAA;EAGf,KAAA,cAA0C,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;EAKpE,KAAA,eAAkD,MAA4B,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;EAgBrF,KAAA,UAAuC,MAAsB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;EAG9E,sBAAsB,gBAAgB,KAAK,eAAc,CAAE,CAAC;EAM5D,KAAK,cAAc,QAAQ,KAAK,GAAG;EACnC,OAAO,UAAU,CAAC,CAAC,gBAAsB,KAAK,cAAc,eAAe,KAAK,GAAG,CAAC;EAEpF,aAAY;GACR,KAAK,OAAM;GACX,KAAK,MAAK;GACV,KAAK,QAAO;GACZ,KAAK,QAAO;GACZ,KAAK,YAAW;GAChB,KAAK,aAAY;GAEjB,KAAK,WAAU;GAEf,gBAAgB,KAAK,eAAc,CAAE;EACzC,CAAC;CACL;CAGA,IACc,cAAW;EACrB,MAAM,UAA0B,KAAK,QAAO;EAE5C,OAAO,YAAY,OAAO,OAAO,OAAO,OAAO;CACnD;CAEA,IACc,cAAW;EACrB,MAAM,QAAuB,KAAK,OAAM;EACxC,MAAM,aAAiC,KAAK,iBAAgB;EAC5D,MAAM,OAAqB,KAAK,KAAI;EAEpC,OAAO;IACF,YAAY;IACZ,GAAG,UAAS,IAAK,UAAU,UAAU;IACrC,GAAG,UAAS,cAAe,eAAe;IAC1C,GAAG,UAAS,UAAW,eAAe;IACtC,GAAG,UAAS,aAAc,KAAK,QAAO;IACtC,GAAG,UAAS,0BAA2B,KAAK,QAAO,KAAM,KAAK,aAAY,MAAO;IACjF,GAAG,UAAS,eAAgB,KAAK,WAAU;IAC3C,GAAG,UAAS,IAAK,SAAS,SAAS;IACnC,GAAG,UAAS,aAAc,KAAK,QAAO,MAAO;EACjD;CACL;CAEA,iBAAc;EACV,MAAM,SAAgD,KAAK,IAAI;EAC/D,MAAM,YAAqB,KAAK,QAAO;EACvC,MAAM,aAAsB,KAAK;EACjC,KAAK,cAAc;EAEnB,IAAI,cAAc,CAAC,WAAW;GAC1B,KAAK,uBAAuB,MAAM;GAClC;EACJ;EAEA,KAAK,cAAc,MAAM;EAEzB,IAAI,WAAW;GACX,KAAK,eAAe,MAAM;GAC1B;EACJ;EAEA,KAAK,oBAAoB,MAAM;CACnC;CAEA,uBAAuB,QAAmB;EACtC,MAAM,YAAgC,KAAK;EAE3C,IAAI,cAAc,MAAM;GACpB,KAAK,gBAAgB,MAAM;GAC3B;EACJ;EAEA,UAAU,MAAM,YAAY,sBAAsB,oBAAmB;EAQrE,IAAI,UAAmB;EAEvB,MAAM,eAAgC;GAClC,IAAI,SACA;GAEJ,UAAU;GACV,UAAU,oBAAoB,gBAAgB,MAAM;GACpD,KAAK,gBAAgB,MAAM;EAC/B;EAEA,UAAU,iBAAiB,gBAAgB,MAAM;EACjD,WAAW,QAAQ,GAAgD;CACvE;CAEA,gBAAgB,QAAmB;EAC/B,KAAK,cAAc,MAAM;EACzB,KAAK,oBAAoB,MAAM;CACnC;CASA,cAAc,QAAmB;EAC7B,MAAM,aAAoC;GAAC,GAAG,UAAS;GAAU,GAAG,UAAS;GAAW,GAAG,UAAS;EAAW;EAI/G,KAAK,MAAM,SAAS,MAAM,KAAK,OAAO,QAAQ,GAC1C,IAAI,WAAW,MAAM,aAA8B,MAAM,UAAU,SAAS,QAAQ,CAAC,GACjF,KAAK,UAAU,YAAY,QAAQ,KAAK;EAIhD,KAAK,UAAU;EACf,KAAK,WAAW;EAChB,KAAK,aAAa;CACtB;CAEA,eAAe,QAAmB;EAC9B,MAAM,cAA6B,KAAK,YAAW;EACnD,MAAM,SAAsB,cAAc,KAAK,YAAY,WAAW,IAAI,KAAK,eAAc;EAE7F,IAAI,KAAK,aAAY,MAAO,QAAQ;GAGhC,KAAK,oBAAoB,MAAM;GAC/B,KAAK,UAAU,SAAS,QAAQ,GAAG,UAAS,SAAU;GACtD,KAAK,UAAU,YAAY,QAAQ,MAAM;GACzC,IAAI,CAAC,aACD,KAAK,aAAa;GAEtB;EACJ;EAEA,IAAI,aAAa;GACb,KAAK,UAAU;GACf,KAAK,UAAU,YAAY,QAAQ,KAAK,OAAO;EACnD,OAAO;GACH,KAAK,aAAa;GAClB,KAAK,UAAU,YAAY,QAAQ,KAAK,UAAU;EACtD;EAEA,MAAM,QAAuB,KAAK,OAAM;EACxC,IAAI,OAAO;GACP,KAAK,WAAW,KAAK,aAAa,KAAK;GACvC,KAAK,UAAU,YAAY,QAAQ,KAAK,QAAQ;EACpD;CACJ;CAEA,oBAAoB,QAAmB;EACnC,MAAM,YAA2B,KAAK,MAAK;EAC3C,MAAM,QAAuB,KAAK,OAAM;EACxC,MAAM,MAAuB,KAAK,QAAO;EAEzC,MAAM,SAA6B,YAAY,KAAK,YAAY,SAAS,IAAI;EAC7E,MAAM,UAA8B,QAAQ,KAAK,aAAa,KAAK,IAAI;EAEvE,IAAI,QAAQ,QAAQ;GAChB,IAAI,QACA,KAAK,UAAU,YAAY,QAAQ,MAAM;GAE7C,IAAI,SACA,KAAK,UAAU,YAAY,QAAQ,OAAO;EAElD,OAAO;GACH,IAAI,SACA,KAAK,UAAU,YAAY,QAAQ,OAAO;GAE9C,IAAI,QACA,KAAK,UAAU,YAAY,QAAQ,MAAM;EAEjD;EAEA,KAAK,UAAU;EACf,KAAK,WAAW;CACpB;CAEA,YAAY,UAAgB;EACxB,MAAM,WAAoC,iBAAiB,MAAM,UAAU,KAAK,cAAc;EAC9F,IAAI,UAAU,SAAS,OACnB,OAAO,KAAK,eAAe,SAAS,IAAI;EAE5C,OAAO,KAAK,aAAa,QAAQ;CACrC;CAEA,eAAe,MAAkB;EAC7B,MAAM,MAAqB,KAAK,KAAK,gBAAgB,8BAA8B,KAAK;EACxF,IAAI,aAAa,aAAa,OAAO;EACrC,IAAI,aAAa,eAAe,MAAM;EACtC,IAAI,aAAa,WAAW,WAAW;EACvC,IAAI,UAAU,IAAI,GAAG,UAAS,OAAQ;EAItC,MAAM,UAA2B,KAAK,WAAW,IAAI;EACrD,KAAK,cAAc,QAAQ,MAAM,OAAO;EAExC,MAAM,MAAqB,KAAK,KAAK,gBAAgB,8BAA8B,KAAK;EACxF,IAAI,aAAa,QAAQ,KAAK,cAAc,WAAW,MAAM,OAAO,CAAC;EACrE,IAAI,YAAY,GAAG;EAEnB,OAAO;CACX;CAOA,WAAW,MAAkB;EAEzB,OAD+B,KAAK,IAAI,cAAc,QAAQ,gCAAgC,MAAM,QAC5E,kBAAkB,IAAI,IAAI,IAAI,aAAa;CACvE;CAGA,aAAa,OAAa;EACtB,MAAM,KAAkB,KAAK,UAAU,cAAc,MAAM;EAC3D,KAAK,UAAU,SAAS,IAAI,GAAG,UAAS,OAAQ;EAChD,KAAK,UAAU,SAAS,IAAI,GAAG,UAAS,QAAS;EACjD,IAAI,CAAC,KAAK,WAAU,GAChB,KAAK,UAAU,SAAS,IAAI,GAAG,UAAS,iBAAkB;EAE9D,KAAK,UAAU,aAAa,IAAI,eAAe,MAAM;EACrD,KAAK,UAAU,YAAY,IAAI,KAAK,UAAU,WAAW,KAAK,CAAC;EAC/D,OAAO;CACX;CAEA,aAAa,MAAY;EACrB,MAAM,KAAkB,KAAK,UAAU,cAAc,MAAM;EAC3D,KAAK,UAAU,SAAS,IAAI,GAAG,UAAS,QAAS;EACjD,KAAK,UAAU,YAAY,IAAI,KAAK,UAAU,WAAW,IAAI,CAAC;EAC9D,OAAO;CACX;CAEA,iBAAc;EACV,MAAM,UAAuB,KAAK,UAAU,cAAc,MAAM;EAChE,KAAK,UAAU,SAAS,SAAS,GAAG,UAAS,UAAW;EAExD,MAAM,SAAsB,KAAK,UAAU,cAAc,MAAM;EAC/D,KAAK,UAAU,SAAS,QAAQ,GAAG,UAAS,iBAAkB;EAC9D,KAAK,UAAU,YAAY,SAAS,MAAM;EAE1C,OAAO;CACX;CAlVS;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAiB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAjB;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAiB,cAAA;GAAA,UAAA;GAAA,QAAA;IAAA,OAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,MAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,OAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,YAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,MAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,aAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,cAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;GAAA;GAAA,MAAA,EAAA,YAAA;IAAA,qBAAA;IAAA,SAAA;GAAA,EAAA;GAAA,WARf,CACP;IACI,SAAS;IACT,kBACI,aAAa,WAAW,OAA0D,GAAG,QAAQ,IAAI;GACxG,CACJ;GAAA,gBAAA,CAAA;IAAA,WAAA,GAAA;IAAA,QAAA,CAAA,kBAAA,gBAAA;GAAA,GAAA;IAAA,WAAA,GAAA;IAAA,QAAA,CAAA,UAAA,QAAA;GAAA,CAAA;GAAA,UAAA;EAAA,CAAA;CAAA;;AAEQ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAiB,YAAA,CAAA;EAhB7B,MAAA;EAAU,MAAA,CAAA;GACP,UAAU;GACV,gBAAgB,CACZ;IAAE,WAAW;IAAmB,QAAQ,CAAC,gBAAgB;GAAC,GAC1D;IAAE,WAAW;IAAmB,QAAQ,CAAC,QAAQ;GAAC,CACrD;GAGD,WAAW,CACP;IACI,SAAS;IACT,kBACI,aAAa,WAAW,OAA0D,GAAG,QAAQ,IAAI;GACxG,CACJ;EACJ,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4GI,MAAA;GAAY,MAAA,CAAA,mBAAmB;;;GAO/B,MAAA;GAAY,MAAA,CAAA,OAAO"}
|
|
@@ -90,7 +90,7 @@ var RtConfirmPopoverComponent = class RtConfirmPopoverComponent {
|
|
|
90
90
|
},
|
|
91
91
|
host: { classAttribute: "rt-confirm-popover" },
|
|
92
92
|
ngImport: i0,
|
|
93
|
-
template: "<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"
|
|
93
|
+
template: "<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"outlined\"\n [label]=\"cancelText()\"\n [attr.aria-label]=\"cancelText()\"\n (click)=\"onCancel()\"></button>\n <button\n rtButton\n qa-dataid=\"confirm-accept\"\n type=\"button\"\n [theme]=\"tone()\"\n [label]=\"confirmText()\"\n [attr.aria-label]=\"confirmText()\"\n (click)=\"onConfirm()\"></button>\n </div>\n</ng-container>\n",
|
|
94
94
|
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-confirm-popover{--rt-confirm-popover-radius: var(--rt-radius-md);--rt-confirm-popover-border-width: var(--rt-border-width-thin);--rt-confirm-popover-shadow: var(--rt-shadow-lg);display:flex;width:280px;max-width:280px;flex-direction:column;padding:var(--rt-space-md);border:var(--rt-confirm-popover-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-confirm-popover-radius);background:var(--rt-color-bg-surface);box-shadow:var(--rt-confirm-popover-shadow);gap:var(--rt-space-sm)}.rt-confirm-popover__title{margin:0;color:var(--rt-color-text-primary);font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-semibold)}.rt-confirm-popover__message{margin:0;color:var(--rt-color-text-primary);font-size:var(--rt-text-sm);line-height:var(--rt-leading-normal)}.rt-confirm-popover__actions{display:flex;justify-content:space-between;gap:var(--rt-space-sm);margin-block-start:var(--rt-space-xs)}}\n"],
|
|
95
95
|
dependencies: [
|
|
96
96
|
{
|
|
@@ -145,7 +145,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
145
145
|
ElemDirective
|
|
146
146
|
],
|
|
147
147
|
host: { class: BEM_BLOCK },
|
|
148
|
-
template: "<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"
|
|
148
|
+
template: "<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"outlined\"\n [label]=\"cancelText()\"\n [attr.aria-label]=\"cancelText()\"\n (click)=\"onCancel()\"></button>\n <button\n rtButton\n qa-dataid=\"confirm-accept\"\n type=\"button\"\n [theme]=\"tone()\"\n [label]=\"confirmText()\"\n [attr.aria-label]=\"confirmText()\"\n (click)=\"onConfirm()\"></button>\n </div>\n</ng-container>\n",
|
|
149
149
|
styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-confirm-popover{--rt-confirm-popover-radius: var(--rt-radius-md);--rt-confirm-popover-border-width: var(--rt-border-width-thin);--rt-confirm-popover-shadow: var(--rt-shadow-lg);display:flex;width:280px;max-width:280px;flex-direction:column;padding:var(--rt-space-md);border:var(--rt-confirm-popover-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-confirm-popover-radius);background:var(--rt-color-bg-surface);box-shadow:var(--rt-confirm-popover-shadow);gap:var(--rt-space-sm)}.rt-confirm-popover__title{margin:0;color:var(--rt-color-text-primary);font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-semibold)}.rt-confirm-popover__message{margin:0;color:var(--rt-color-text-primary);font-size:var(--rt-text-sm);line-height:var(--rt-leading-normal)}.rt-confirm-popover__actions{display:flex;justify-content:space-between;gap:var(--rt-space-sm);margin-block-start:var(--rt-space-xs)}}\n"]
|
|
150
150
|
}]
|
|
151
151
|
}],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rt-tools-ui-kit-v2-confirm-popover.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm-popover.component.ts","../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm-popover.component.html","../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm.directive.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n InputSignal,\n output,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { IRtConfirmPopover } from './rt-confirm-popover.model';\n\nconst BEM_BLOCK: string = 'rt-confirm-popover';\n\n/**\n * Презентационная панель подтверждения. Рендерится директивой `[rtConfirm]`\n * через CDK `ComponentPortal` под host-кнопкой. Содержит опциональный заголовок,\n * текст вопроса и две кнопки: «Отмена» (text/secondary) и подтверждающую\n * (`tone` — danger по умолчанию для деструктивных действий).\n *\n * `ViewEncapsulation.None` — стили префиксованы `.rt-confirm-popover`. Inputs\n * выставляются директивой через `setInput`; outputs (`confirm`/`cancel`) она\n * слушает и транслирует в `(confirmed)` / закрытие.\n */\n@Component({\n selector: 'rt-confirm-popover',\n templateUrl: './rt-confirm-popover.component.html',\n styleUrl: './rt-confirm-popover.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [RtButtonDirective, BlockDirective, ElemDirective],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtConfirmPopoverComponent {\n readonly #t_uiConfirm: Signal<string> = rtKitLabel('uiConfirm');\n readonly #t_uiCancel: Signal<string> = rtKitLabel('uiCancel');\n\n protected readonly confirmText: Signal<string> = computed((): string => this.confirmLabel() || this.#t_uiConfirm());\n protected readonly cancelText: Signal<string> = computed((): string => this.cancelLabel() || this.#t_uiCancel());\n\n public readonly message: InputSignal<string> = input<string>('');\n\n public readonly title: InputSignal<string | null> = input<string | null>(null);\n\n /** Пусто — берётся переведённая подпись по умолчанию */\n public readonly confirmLabel: InputSignal<string> = input<string>('');\n\n public readonly cancelLabel: InputSignal<string> = input<string>('');\n\n public readonly tone: InputSignal<IRtConfirmPopover.Tone> = input<IRtConfirmPopover.Tone>('danger');\n\n public readonly accepted: OutputEmitterRef<void> = output<void>();\n\n public readonly cancelled: OutputEmitterRef<void> = output<void>();\n\n protected onConfirm(): void {\n this.accepted.emit();\n }\n\n protected onCancel(): void {\n this.cancelled.emit();\n }\n}\n","<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n [label]=\"cancelText()\"\n [attr.aria-label]=\"cancelText()\"\n (click)=\"onCancel()\"></button>\n <button\n rtButton\n qa-dataid=\"confirm-accept\"\n type=\"button\"\n [theme]=\"tone()\"\n [label]=\"confirmText()\"\n [attr.aria-label]=\"confirmText()\"\n (click)=\"onConfirm()\"></button>\n </div>\n</ng-container>\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n ConnectedPosition,\n FlexibleConnectedPositionStrategy,\n Overlay,\n OverlayConfig,\n OverlayRef,\n ScrollStrategyOptions,\n} from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport {\n booleanAttribute,\n ComponentRef,\n DestroyRef,\n Directive,\n ElementRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n OnDestroy,\n output,\n OutputEmitterRef,\n signal,\n Signal,\n WritableSignal,\n} from '@angular/core';\nimport { outputToObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { map, merge, Observable, Subject, switchMap } from 'rxjs';\n\nimport { setRtComponentInputs } from '@rt-tools/core';\n\nimport { carryThemeScope, materialPresetClassesOf } from '@rt-tools/ui-kit-v2/core';\nimport { RtConfirmPopoverComponent } from './rt-confirm-popover.component';\nimport { IRtConfirmPopover } from './rt-confirm-popover.model';\n\nconst VIEWPORT_MARGIN: number = 8;\n\n/**\n * Confirm-popover директива поверх CDK Overlay. Вешается на host-кнопку\n * (обычно `rt-icon-button` деструктивного действия). По клику показывает прямо\n * под кнопкой панель `rt-confirm-popover` с вопросом и кнопками\n * «Отмена» / подтверждение. Подтверждение → `(confirmed)` + закрытие; отмена,\n * outside-click, Escape → просто закрытие.\n *\n * Движок — CDK `flexibleConnectedTo` (end-выравнивание + flip), чтобы панель у\n * правого края aside'а раскрывалась влево и не резалась `overflow: hidden`.\n *\n * @example\n * ```html\n * <rt-icon-button\n * icon=\"ico-error\"\n * variant=\"danger\"\n * ariaLabel=\"Отклонить\"\n * tooltip=\"Отклонить\"\n * [rtConfirm]=\"'Отклонить заявку? Оператор получит уведомление.'\"\n * rtConfirmTitle=\"Отклонить заявку\"\n * rtConfirmLabel=\"Отклонить\"\n * (confirmed)=\"rejectTour()\" />\n * ```\n */\n@Directive({\n selector: '[rtConfirm]',\n exportAs: 'rtConfirm',\n host: {\n '(click)': 'onHostClick()',\n },\n})\nexport class RtConfirmDirective implements OnDestroy {\n readonly #overlay: Overlay = inject(Overlay);\n readonly #elementRef: ElementRef<HTMLElement> = inject<ElementRef<HTMLElement>>(ElementRef);\n readonly #scrollStrategies: ScrollStrategyOptions = inject(ScrollStrategyOptions);\n readonly #destroyRef: DestroyRef = inject(DestroyRef);\n\n readonly #overlayCreatedSource: Subject<OverlayRef> = new Subject<OverlayRef>();\n readonly #panelAttachedSource: Subject<ComponentRef<RtConfirmPopoverComponent>> = new Subject<\n ComponentRef<RtConfirmPopoverComponent>\n >();\n\n #overlayRef: OverlayRef | null = null;\n #panelRef: ComponentRef<RtConfirmPopoverComponent> | null = null;\n\n protected readonly isOpenState: WritableSignal<boolean> = signal<boolean>(false);\n\n public readonly message: InputSignal<string> = input<string>('', { alias: 'rtConfirm' });\n\n public readonly title: InputSignal<string | null> = input<string | null>(null, {\n alias: 'rtConfirmTitle',\n });\n\n /** Пусто — панель подставит переведённое умолчание */\n public readonly label: InputSignal<string> = input<string>('', {\n alias: 'rtConfirmLabel',\n });\n\n public readonly cancelLabel: InputSignal<string> = input<string>('', {\n alias: 'rtConfirmCancelLabel',\n });\n\n public readonly tone: InputSignal<IRtConfirmPopover.Tone> = input<IRtConfirmPopover.Tone>('danger', { alias: 'rtConfirmTone' });\n\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n alias: 'rtConfirmDisabled',\n transform: booleanAttribute,\n });\n\n public readonly confirmed: OutputEmitterRef<void> = output<void>();\n\n public readonly isOpen: Signal<boolean> = this.isOpenState.asReadonly();\n\n constructor() {\n // Per-attach подписки на outputs панели (accepted / cancelled) живут в\n // одном конструкторном стриме: open() эмитит свежий ComponentRef,\n // switchMap переключается на его outputs (предыдущая панель к этому\n // моменту уже detach'нута — outputs комплитятся при destroy componentRef).\n // Бэкстоп takeUntilDestroyed — на жизнь директивы.\n this.#panelAttachedSource\n .pipe(\n switchMap((panelRef: ComponentRef<RtConfirmPopoverComponent>): Observable<() => void> =>\n merge(\n outputToObservable(panelRef.instance.accepted).pipe(\n map((): (() => void) => (): void => {\n this.confirmed.emit();\n this.close();\n })\n ),\n outputToObservable(panelRef.instance.cancelled).pipe(map((): (() => void) => (): void => this.close()))\n )\n ),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((handleCloseIntent: () => void): void => handleCloseIntent());\n\n // Outside-click / ESC подписки на единожды создаваемый overlay:\n // #ensureOverlay эмитит OverlayRef после создания (ровно один раз за\n // жизнь директивы), стрим живёт до destroy директивы.\n this.#overlayCreatedSource\n .pipe(\n switchMap((overlayRef: OverlayRef): Observable<() => void> =>\n merge(\n overlayRef.outsidePointerEvents().pipe(\n map((event: MouseEvent): (() => void) => (): void => {\n // Клик по host обрабатывает onHostClick (toggle) — не закрываем\n // здесь, иначе двойной toggle.\n if (this.#elementRef.nativeElement.contains(event.target as Node)) {\n return;\n }\n this.close();\n })\n ),\n overlayRef.keydownEvents().pipe(\n map((event: KeyboardEvent): (() => void) => (): void => {\n if (event.key === 'Escape') {\n event.preventDefault();\n this.close();\n }\n })\n )\n )\n ),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((handleCloseIntent: () => void): void => handleCloseIntent());\n }\n\n public ngOnDestroy(): void {\n this.#disposeOverlay();\n }\n\n public open(): void {\n if (this.disabled() || this.isOpenState() || this.message().trim() === '') {\n return;\n }\n const overlayRef: OverlayRef = this.#ensureOverlay();\n // Коробка переживает закрытие, а кусок темы вокруг host'а мог смениться — переносим на каждом открытии.\n carryThemeScope(overlayRef.overlayElement, this.#elementRef.nativeElement);\n const portal: ComponentPortal<RtConfirmPopoverComponent> = new ComponentPortal(RtConfirmPopoverComponent);\n this.#panelRef = overlayRef.attach(portal);\n // Одним набором, а не пятью строками с именами: имя, написанное строкой, не проверяет\n // ничто — опечатка собирается и падает на подъёме сообщением о входе, которого нет.\n setRtComponentInputs(this.#panelRef, {\n message: this.message(),\n title: this.title(),\n confirmLabel: this.label(),\n cancelLabel: this.cancelLabel(),\n tone: this.tone(),\n });\n\n // Подписки на accepted/cancelled объявлены один раз в конструкторе —\n // здесь только эмит свежего ComponentRef (см. #panelAttachedSource-стрим).\n this.#panelAttachedSource.next(this.#panelRef);\n\n this.isOpenState.set(true);\n }\n\n public close(): void {\n if (!this.isOpenState()) {\n return;\n }\n this.#overlayRef?.detach();\n this.#panelRef = null;\n this.isOpenState.set(false);\n }\n\n protected onHostClick(): void {\n if (this.disabled()) {\n return;\n }\n if (this.isOpenState()) {\n this.close();\n } else {\n this.open();\n }\n }\n\n #ensureOverlay(): OverlayRef {\n if (this.#overlayRef !== null) {\n return this.#overlayRef;\n }\n const positions: ConnectedPosition[] = [\n {\n originX: 'end',\n originY: 'bottom',\n overlayX: 'end',\n overlayY: 'top',\n offsetY: 6,\n },\n {\n originX: 'end',\n originY: 'top',\n overlayX: 'end',\n overlayY: 'bottom',\n offsetY: -6,\n },\n ];\n const positionStrategy: FlexibleConnectedPositionStrategy = this.#overlay\n .position()\n .flexibleConnectedTo(this.#elementRef)\n .withPush(true)\n .withViewportMargin(VIEWPORT_MARGIN)\n .withFlexibleDimensions(false)\n .withPositions(positions);\n\n const config: OverlayConfig = new OverlayConfig({\n positionStrategy,\n scrollStrategy: this.#scrollStrategies.reposition(),\n hasBackdrop: false,\n panelClass: ['rt-confirm-popover-panel', ...materialPresetClassesOf(this.#elementRef.nativeElement)],\n });\n const overlayRef: OverlayRef = this.#overlay.create(config);\n\n // Outside-click / ESC подписки объявлены один раз в конструкторе —\n // здесь только эмит созданного OverlayRef (см. #overlayCreatedSource-стрим).\n this.#overlayCreatedSource.next(overlayRef);\n\n this.#overlayRef = overlayRef;\n return overlayRef;\n }\n\n #disposeOverlay(): void {\n this.#overlayRef?.dispose();\n this.#overlayRef = null;\n this.#panelRef = null;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rt-tools-ui-kit-v2-confirm-popover.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm-popover.component.ts","../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm-popover.component.html","../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm.directive.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n InputSignal,\n output,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { IRtConfirmPopover } from './rt-confirm-popover.model';\n\nconst BEM_BLOCK: string = 'rt-confirm-popover';\n\n/**\n * Презентационная панель подтверждения. Рендерится директивой `[rtConfirm]`\n * через CDK `ComponentPortal` под host-кнопкой. Содержит опциональный заголовок,\n * текст вопроса и две кнопки: «Отмена» (text/secondary) и подтверждающую\n * (`tone` — danger по умолчанию для деструктивных действий).\n *\n * `ViewEncapsulation.None` — стили префиксованы `.rt-confirm-popover`. Inputs\n * выставляются директивой через `setInput`; outputs (`confirm`/`cancel`) она\n * слушает и транслирует в `(confirmed)` / закрытие.\n */\n@Component({\n selector: 'rt-confirm-popover',\n templateUrl: './rt-confirm-popover.component.html',\n styleUrl: './rt-confirm-popover.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [RtButtonDirective, BlockDirective, ElemDirective],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtConfirmPopoverComponent {\n readonly #t_uiConfirm: Signal<string> = rtKitLabel('uiConfirm');\n readonly #t_uiCancel: Signal<string> = rtKitLabel('uiCancel');\n\n protected readonly confirmText: Signal<string> = computed((): string => this.confirmLabel() || this.#t_uiConfirm());\n protected readonly cancelText: Signal<string> = computed((): string => this.cancelLabel() || this.#t_uiCancel());\n\n public readonly message: InputSignal<string> = input<string>('');\n\n public readonly title: InputSignal<string | null> = input<string | null>(null);\n\n /** Пусто — берётся переведённая подпись по умолчанию */\n public readonly confirmLabel: InputSignal<string> = input<string>('');\n\n public readonly cancelLabel: InputSignal<string> = input<string>('');\n\n public readonly tone: InputSignal<IRtConfirmPopover.Tone> = input<IRtConfirmPopover.Tone>('danger');\n\n public readonly accepted: OutputEmitterRef<void> = output<void>();\n\n public readonly cancelled: OutputEmitterRef<void> = output<void>();\n\n protected onConfirm(): void {\n this.accepted.emit();\n }\n\n protected onCancel(): void {\n this.cancelled.emit();\n }\n}\n","<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"outlined\"\n [label]=\"cancelText()\"\n [attr.aria-label]=\"cancelText()\"\n (click)=\"onCancel()\"></button>\n <button\n rtButton\n qa-dataid=\"confirm-accept\"\n type=\"button\"\n [theme]=\"tone()\"\n [label]=\"confirmText()\"\n [attr.aria-label]=\"confirmText()\"\n (click)=\"onConfirm()\"></button>\n </div>\n</ng-container>\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n ConnectedPosition,\n FlexibleConnectedPositionStrategy,\n Overlay,\n OverlayConfig,\n OverlayRef,\n ScrollStrategyOptions,\n} from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport {\n booleanAttribute,\n ComponentRef,\n DestroyRef,\n Directive,\n ElementRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n OnDestroy,\n output,\n OutputEmitterRef,\n signal,\n Signal,\n WritableSignal,\n} from '@angular/core';\nimport { outputToObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { map, merge, Observable, Subject, switchMap } from 'rxjs';\n\nimport { setRtComponentInputs } from '@rt-tools/core';\n\nimport { carryThemeScope, materialPresetClassesOf } from '@rt-tools/ui-kit-v2/core';\nimport { RtConfirmPopoverComponent } from './rt-confirm-popover.component';\nimport { IRtConfirmPopover } from './rt-confirm-popover.model';\n\nconst VIEWPORT_MARGIN: number = 8;\n\n/**\n * Confirm-popover директива поверх CDK Overlay. Вешается на host-кнопку\n * (обычно `rt-icon-button` деструктивного действия). По клику показывает прямо\n * под кнопкой панель `rt-confirm-popover` с вопросом и кнопками\n * «Отмена» / подтверждение. Подтверждение → `(confirmed)` + закрытие; отмена,\n * outside-click, Escape → просто закрытие.\n *\n * Движок — CDK `flexibleConnectedTo` (end-выравнивание + flip), чтобы панель у\n * правого края aside'а раскрывалась влево и не резалась `overflow: hidden`.\n *\n * @example\n * ```html\n * <rt-icon-button\n * icon=\"ico-error\"\n * variant=\"danger\"\n * ariaLabel=\"Отклонить\"\n * tooltip=\"Отклонить\"\n * [rtConfirm]=\"'Отклонить заявку? Оператор получит уведомление.'\"\n * rtConfirmTitle=\"Отклонить заявку\"\n * rtConfirmLabel=\"Отклонить\"\n * (confirmed)=\"rejectTour()\" />\n * ```\n */\n@Directive({\n selector: '[rtConfirm]',\n exportAs: 'rtConfirm',\n host: {\n '(click)': 'onHostClick()',\n },\n})\nexport class RtConfirmDirective implements OnDestroy {\n readonly #overlay: Overlay = inject(Overlay);\n readonly #elementRef: ElementRef<HTMLElement> = inject<ElementRef<HTMLElement>>(ElementRef);\n readonly #scrollStrategies: ScrollStrategyOptions = inject(ScrollStrategyOptions);\n readonly #destroyRef: DestroyRef = inject(DestroyRef);\n\n readonly #overlayCreatedSource: Subject<OverlayRef> = new Subject<OverlayRef>();\n readonly #panelAttachedSource: Subject<ComponentRef<RtConfirmPopoverComponent>> = new Subject<\n ComponentRef<RtConfirmPopoverComponent>\n >();\n\n #overlayRef: OverlayRef | null = null;\n #panelRef: ComponentRef<RtConfirmPopoverComponent> | null = null;\n\n protected readonly isOpenState: WritableSignal<boolean> = signal<boolean>(false);\n\n public readonly message: InputSignal<string> = input<string>('', { alias: 'rtConfirm' });\n\n public readonly title: InputSignal<string | null> = input<string | null>(null, {\n alias: 'rtConfirmTitle',\n });\n\n /** Пусто — панель подставит переведённое умолчание */\n public readonly label: InputSignal<string> = input<string>('', {\n alias: 'rtConfirmLabel',\n });\n\n public readonly cancelLabel: InputSignal<string> = input<string>('', {\n alias: 'rtConfirmCancelLabel',\n });\n\n public readonly tone: InputSignal<IRtConfirmPopover.Tone> = input<IRtConfirmPopover.Tone>('danger', { alias: 'rtConfirmTone' });\n\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n alias: 'rtConfirmDisabled',\n transform: booleanAttribute,\n });\n\n public readonly confirmed: OutputEmitterRef<void> = output<void>();\n\n public readonly isOpen: Signal<boolean> = this.isOpenState.asReadonly();\n\n constructor() {\n // Per-attach подписки на outputs панели (accepted / cancelled) живут в\n // одном конструкторном стриме: open() эмитит свежий ComponentRef,\n // switchMap переключается на его outputs (предыдущая панель к этому\n // моменту уже detach'нута — outputs комплитятся при destroy componentRef).\n // Бэкстоп takeUntilDestroyed — на жизнь директивы.\n this.#panelAttachedSource\n .pipe(\n switchMap((panelRef: ComponentRef<RtConfirmPopoverComponent>): Observable<() => void> =>\n merge(\n outputToObservable(panelRef.instance.accepted).pipe(\n map((): (() => void) => (): void => {\n this.confirmed.emit();\n this.close();\n })\n ),\n outputToObservable(panelRef.instance.cancelled).pipe(map((): (() => void) => (): void => this.close()))\n )\n ),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((handleCloseIntent: () => void): void => handleCloseIntent());\n\n // Outside-click / ESC подписки на единожды создаваемый overlay:\n // #ensureOverlay эмитит OverlayRef после создания (ровно один раз за\n // жизнь директивы), стрим живёт до destroy директивы.\n this.#overlayCreatedSource\n .pipe(\n switchMap((overlayRef: OverlayRef): Observable<() => void> =>\n merge(\n overlayRef.outsidePointerEvents().pipe(\n map((event: MouseEvent): (() => void) => (): void => {\n // Клик по host обрабатывает onHostClick (toggle) — не закрываем\n // здесь, иначе двойной toggle.\n if (this.#elementRef.nativeElement.contains(event.target as Node)) {\n return;\n }\n this.close();\n })\n ),\n overlayRef.keydownEvents().pipe(\n map((event: KeyboardEvent): (() => void) => (): void => {\n if (event.key === 'Escape') {\n event.preventDefault();\n this.close();\n }\n })\n )\n )\n ),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((handleCloseIntent: () => void): void => handleCloseIntent());\n }\n\n public ngOnDestroy(): void {\n this.#disposeOverlay();\n }\n\n public open(): void {\n if (this.disabled() || this.isOpenState() || this.message().trim() === '') {\n return;\n }\n const overlayRef: OverlayRef = this.#ensureOverlay();\n // Коробка переживает закрытие, а кусок темы вокруг host'а мог смениться — переносим на каждом открытии.\n carryThemeScope(overlayRef.overlayElement, this.#elementRef.nativeElement);\n const portal: ComponentPortal<RtConfirmPopoverComponent> = new ComponentPortal(RtConfirmPopoverComponent);\n this.#panelRef = overlayRef.attach(portal);\n // Одним набором, а не пятью строками с именами: имя, написанное строкой, не проверяет\n // ничто — опечатка собирается и падает на подъёме сообщением о входе, которого нет.\n setRtComponentInputs(this.#panelRef, {\n message: this.message(),\n title: this.title(),\n confirmLabel: this.label(),\n cancelLabel: this.cancelLabel(),\n tone: this.tone(),\n });\n\n // Подписки на accepted/cancelled объявлены один раз в конструкторе —\n // здесь только эмит свежего ComponentRef (см. #panelAttachedSource-стрим).\n this.#panelAttachedSource.next(this.#panelRef);\n\n this.isOpenState.set(true);\n }\n\n public close(): void {\n if (!this.isOpenState()) {\n return;\n }\n this.#overlayRef?.detach();\n this.#panelRef = null;\n this.isOpenState.set(false);\n }\n\n protected onHostClick(): void {\n if (this.disabled()) {\n return;\n }\n if (this.isOpenState()) {\n this.close();\n } else {\n this.open();\n }\n }\n\n #ensureOverlay(): OverlayRef {\n if (this.#overlayRef !== null) {\n return this.#overlayRef;\n }\n const positions: ConnectedPosition[] = [\n {\n originX: 'end',\n originY: 'bottom',\n overlayX: 'end',\n overlayY: 'top',\n offsetY: 6,\n },\n {\n originX: 'end',\n originY: 'top',\n overlayX: 'end',\n overlayY: 'bottom',\n offsetY: -6,\n },\n ];\n const positionStrategy: FlexibleConnectedPositionStrategy = this.#overlay\n .position()\n .flexibleConnectedTo(this.#elementRef)\n .withPush(true)\n .withViewportMargin(VIEWPORT_MARGIN)\n .withFlexibleDimensions(false)\n .withPositions(positions);\n\n const config: OverlayConfig = new OverlayConfig({\n positionStrategy,\n scrollStrategy: this.#scrollStrategies.reposition(),\n hasBackdrop: false,\n panelClass: ['rt-confirm-popover-panel', ...materialPresetClassesOf(this.#elementRef.nativeElement)],\n });\n const overlayRef: OverlayRef = this.#overlay.create(config);\n\n // Outside-click / ESC подписки объявлены один раз в конструкторе —\n // здесь только эмит созданного OverlayRef (см. #overlayCreatedSource-стрим).\n this.#overlayCreatedSource.next(overlayRef);\n\n this.#overlayRef = overlayRef;\n return overlayRef;\n }\n\n #disposeOverlay(): void {\n this.#overlayRef?.dispose();\n this.#overlayRef = null;\n this.#panelRef = null;\n }\n}\n"],"mappings":"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"}
|
|
@@ -40,12 +40,16 @@ const RT_KIT_LABELS_EN = {
|
|
|
40
40
|
aiLike: "Good answer",
|
|
41
41
|
aiNewThread: "New conversation",
|
|
42
42
|
aiNoThreads: "No conversations yet",
|
|
43
|
+
aiPromptEffortAria: "Effort",
|
|
44
|
+
aiPromptModeAria: "Mode",
|
|
45
|
+
aiPromptModelAria: "Model",
|
|
43
46
|
aiReference: "Reference",
|
|
44
47
|
aiRetry: "Ask again",
|
|
45
48
|
aiSearchThreads: "Search conversations",
|
|
46
49
|
aiShowSteps: "Show steps",
|
|
47
50
|
aiThreads: "Conversations",
|
|
48
51
|
aiTitle: "Assistant",
|
|
52
|
+
aiUsageAria: "Used {{percent}}% of the limit",
|
|
49
53
|
aiYou: "You",
|
|
50
54
|
asideCopyErrorInfo: "Copy error info",
|
|
51
55
|
asideRequestError: "Request Error",
|
|
@@ -641,6 +645,8 @@ function rtTreeToggle(open, value) {
|
|
|
641
645
|
}
|
|
642
646
|
const RT_NARROW_WIDTH = 1080;
|
|
643
647
|
const NARROW_VIEWPORT_QUERY = `(max-width: ${RT_NARROW_WIDTH}px)`;
|
|
648
|
+
const RT_PHONE_WIDTH = 480;
|
|
649
|
+
const PHONE_VIEWPORT_QUERY = `(max-width: 480px)`;
|
|
644
650
|
function rtNarrowByWidth(placeWidth, viewportNarrow) {
|
|
645
651
|
return placeWidth === null ? viewportNarrow : placeWidth <= RT_NARROW_WIDTH;
|
|
646
652
|
}
|
|
@@ -655,6 +661,7 @@ var BreakpointsService = class BreakpointsService {
|
|
|
655
661
|
this.tablet = toSignal(this.#match([Breakpoints.TabletPortrait, Breakpoints.TabletLandscape]), { initialValue: false });
|
|
656
662
|
this.desktop = toSignal(this.#match([Breakpoints.WebPortrait, Breakpoints.WebLandscape]), { initialValue: true });
|
|
657
663
|
this.viewportNarrow = toSignal(this.#match([NARROW_VIEWPORT_QUERY]), { initialValue: false });
|
|
664
|
+
this.phone = toSignal(this.#match([PHONE_VIEWPORT_QUERY]), { initialValue: false });
|
|
658
665
|
this.narrow = computed(() => rtNarrowByWidth(this.#placeWidth(), this.viewportNarrow()), ...ngDevMode ? [{ debugName: "narrow" }] : /* istanbul ignore next */ []);
|
|
659
666
|
}
|
|
660
667
|
#observer;
|
|
@@ -2003,6 +2010,21 @@ const ALLOWED_SCHEMES = [
|
|
|
2003
2010
|
"https://",
|
|
2004
2011
|
"mailto:"
|
|
2005
2012
|
];
|
|
2013
|
+
const BARE_SCHEMES = ["http://", "https://"];
|
|
2014
|
+
const TRAILING_PUNCTUATION = /* @__PURE__ */ new Set([
|
|
2015
|
+
".",
|
|
2016
|
+
",",
|
|
2017
|
+
";",
|
|
2018
|
+
":",
|
|
2019
|
+
"!",
|
|
2020
|
+
"?",
|
|
2021
|
+
"'",
|
|
2022
|
+
"\"",
|
|
2023
|
+
"»",
|
|
2024
|
+
")",
|
|
2025
|
+
"]"
|
|
2026
|
+
]);
|
|
2027
|
+
const WORD_CHAR = /[\p{L}\p{N}]/u;
|
|
2006
2028
|
const PAIRED_MARKS = [
|
|
2007
2029
|
{
|
|
2008
2030
|
mark: "`",
|
|
@@ -2055,6 +2077,39 @@ function isAllowedHref(value) {
|
|
|
2055
2077
|
const lowered = value.toLowerCase();
|
|
2056
2078
|
return ALLOWED_SCHEMES.some((scheme) => lowered.startsWith(scheme));
|
|
2057
2079
|
}
|
|
2080
|
+
function isWordChar(source, index) {
|
|
2081
|
+
return index >= 0 && index < source.length && WORD_CHAR.test(source[index]);
|
|
2082
|
+
}
|
|
2083
|
+
function unlink(nodes) {
|
|
2084
|
+
return nodes.flatMap((node) => node.kind === ERtMarkdownInline.Link ? unlink(node.children) : [{
|
|
2085
|
+
...node,
|
|
2086
|
+
children: unlink(node.children)
|
|
2087
|
+
}]);
|
|
2088
|
+
}
|
|
2089
|
+
function countOf(value, sign) {
|
|
2090
|
+
return value.split(sign).length - 1;
|
|
2091
|
+
}
|
|
2092
|
+
function readBareUrl(source, start) {
|
|
2093
|
+
if (source[start]?.toLowerCase() !== "h" || isWordChar(source, start - 1)) return null;
|
|
2094
|
+
const rest = source.slice(start);
|
|
2095
|
+
const lowered = rest.toLowerCase();
|
|
2096
|
+
const scheme = BARE_SCHEMES.find((candidate) => lowered.startsWith(candidate));
|
|
2097
|
+
if (scheme === void 0) return null;
|
|
2098
|
+
const whole = rest.split(/\s/u, 1)[0];
|
|
2099
|
+
let address = whole;
|
|
2100
|
+
while (address.length > 0 && TRAILING_PUNCTUATION.has(address[address.length - 1])) address = address.slice(0, -1);
|
|
2101
|
+
while (address.length < whole.length && whole[address.length] === ")" && countOf(address, "(") > countOf(address, ")")) address += ")";
|
|
2102
|
+
if (address.length <= scheme.length) return null;
|
|
2103
|
+
return {
|
|
2104
|
+
length: address.length,
|
|
2105
|
+
node: {
|
|
2106
|
+
kind: ERtMarkdownInline.Link,
|
|
2107
|
+
text: address,
|
|
2108
|
+
children: [textNode(address)],
|
|
2109
|
+
href: address
|
|
2110
|
+
}
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2058
2113
|
function readImage(source, start) {
|
|
2059
2114
|
if (source[start] !== "!" || source[start + 1] !== "[") return null;
|
|
2060
2115
|
const close = source.indexOf("]", start + 2);
|
|
@@ -2079,16 +2134,23 @@ function readLink(source, start, nested) {
|
|
|
2079
2134
|
node: {
|
|
2080
2135
|
kind: ERtMarkdownInline.Link,
|
|
2081
2136
|
text: label,
|
|
2082
|
-
children: nested(label),
|
|
2137
|
+
children: unlink(nested(label)),
|
|
2083
2138
|
href: address
|
|
2084
2139
|
}
|
|
2085
2140
|
};
|
|
2086
2141
|
}
|
|
2142
|
+
function findClose(source, mark, from, intraword) {
|
|
2143
|
+
let close = source.indexOf(mark, from);
|
|
2144
|
+
while (intraword && close !== -1 && isWordChar(source, close + mark.length)) close = source.indexOf(mark, close + 1);
|
|
2145
|
+
return close;
|
|
2146
|
+
}
|
|
2087
2147
|
function readPaired(source, start, nested) {
|
|
2088
2148
|
const pair = PAIRED_MARKS.find((candidate) => source.startsWith(candidate.mark, start));
|
|
2089
2149
|
if (pair === void 0) return null;
|
|
2150
|
+
const intraword = pair.mark.startsWith("_");
|
|
2151
|
+
if (intraword && isWordChar(source, start - 1)) return null;
|
|
2090
2152
|
const from = start + pair.mark.length;
|
|
2091
|
-
const close = source
|
|
2153
|
+
const close = findClose(source, pair.mark, from, intraword);
|
|
2092
2154
|
if (close === -1 || close === from) return null;
|
|
2093
2155
|
const inner = source.slice(from, close);
|
|
2094
2156
|
return {
|
|
@@ -2102,7 +2164,7 @@ function readPaired(source, start, nested) {
|
|
|
2102
2164
|
};
|
|
2103
2165
|
}
|
|
2104
2166
|
function readAt(source, index, nested) {
|
|
2105
|
-
return readImage(source, index) ?? readLink(source, index, nested) ?? readPaired(source, index, nested) ?? {
|
|
2167
|
+
return readImage(source, index) ?? readLink(source, index, nested) ?? readBareUrl(source, index) ?? readPaired(source, index, nested) ?? {
|
|
2106
2168
|
length: 1,
|
|
2107
2169
|
node: null
|
|
2108
2170
|
};
|
|
@@ -2828,6 +2890,6 @@ const iconsName = [
|
|
|
2828
2890
|
"window-maximize",
|
|
2829
2891
|
"window-minimize"
|
|
2830
2892
|
];
|
|
2831
|
-
export { BreakpointsService, ERtDataTableCellColor, ERtDataTableColumnType, ERtDataTableFilterType, ERtMarkdownBlock, ERtMarkdownInline, ERtStorageKeys, MessageBus, NotificationBus, NotificationRef, RT_CONSUMER_HANDLE_NAMES, RT_DATA_TABLE_PRESET_FROM_HOST, RT_DESIGN_TOKEN_NAMES, RT_KIT_CONFIG, RT_KIT_LABELS, RT_KIT_LABELS_EN, RT_KIT_LOCALE, RT_KIT_TRANSLATOR, RT_MATERIAL_PRESET_CLASS, RT_MATERIAL_PRESET_SELECTOR, RT_NARROW_WIDTH, RT_PRESET_MATERIAL_CLASS, RT_RADIUS_DEFAULT, RT_RADIUS_STEPS, RT_THEME_SCOPE_ATTRIBUTE, RtDayStampPipe, RtInfiniteScrollDirective, RtKitLabelPipe, RtOptionList, RtThemeScopeDirective, SEARCH_DEBOUNCE_MS, ThemeService, breakNode, carryThemeScope, carryThemeScopeOfFocus, coerceQuillDeltaOutput, fileNameFromUrl, formatFileSize, iconsName, markdownToPlainText, materialPresetClassesOf, materialPresetClassesOfFocus, normalizeQuillDelta, parseInline, parseMarkdown, provideRtKit, provideRtKitLabels, rtKitDefault, rtKitLabel, rtMatchParts, rtNarrowByWidth, rtScrollActiveOptionIntoView, rtSearchFold, rtSearchMatches, rtSearchWords, rtTreeBranchState, rtTreeFind, rtTreeIsTree, rtTreeLeaves, rtTreeOpenFor, rtTreeRows, rtTreeSideKey, rtTreeToggle, searchDebounce, themeScopeOf, themeScopeOfFocus };
|
|
2893
|
+
export { BreakpointsService, ERtDataTableCellColor, ERtDataTableColumnType, ERtDataTableFilterType, ERtMarkdownBlock, ERtMarkdownInline, ERtStorageKeys, MessageBus, NotificationBus, NotificationRef, RT_CONSUMER_HANDLE_NAMES, RT_DATA_TABLE_PRESET_FROM_HOST, RT_DESIGN_TOKEN_NAMES, RT_KIT_CONFIG, RT_KIT_LABELS, RT_KIT_LABELS_EN, RT_KIT_LOCALE, RT_KIT_TRANSLATOR, RT_MATERIAL_PRESET_CLASS, RT_MATERIAL_PRESET_SELECTOR, RT_NARROW_WIDTH, RT_PHONE_WIDTH, RT_PRESET_MATERIAL_CLASS, RT_RADIUS_DEFAULT, RT_RADIUS_STEPS, RT_THEME_SCOPE_ATTRIBUTE, RtDayStampPipe, RtInfiniteScrollDirective, RtKitLabelPipe, RtOptionList, RtThemeScopeDirective, SEARCH_DEBOUNCE_MS, ThemeService, breakNode, carryThemeScope, carryThemeScopeOfFocus, coerceQuillDeltaOutput, fileNameFromUrl, formatFileSize, iconsName, markdownToPlainText, materialPresetClassesOf, materialPresetClassesOfFocus, normalizeQuillDelta, parseInline, parseMarkdown, provideRtKit, provideRtKitLabels, rtKitDefault, rtKitLabel, rtMatchParts, rtNarrowByWidth, rtScrollActiveOptionIntoView, rtSearchFold, rtSearchMatches, rtSearchWords, rtTreeBranchState, rtTreeFind, rtTreeIsTree, rtTreeLeaves, rtTreeOpenFor, rtTreeRows, rtTreeSideKey, rtTreeToggle, searchDebounce, themeScopeOf, themeScopeOfFocus };
|
|
2832
2894
|
|
|
2833
2895
|
//# sourceMappingURL=rt-tools-ui-kit-v2-core.mjs.map
|