@konce-pt/react 0.11.2 → 0.14.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/README.md +128 -64
- package/dist/accordion/accordion.d.ts +14 -6
- package/dist/accordion/accordion.js +25 -17
- package/dist/accordion/llms.txt +22 -10
- package/dist/alert/alert.d.ts +2 -2
- package/dist/alert/alert.js +3 -2
- package/dist/alert/llms.txt +10 -9
- package/dist/app-shell/app-shell.d.ts +14 -14
- package/dist/app-shell/app-shell.js +22 -15
- package/dist/app-shell/llms.txt +16 -15
- package/dist/auth/auth-types.d.ts +6 -6
- package/dist/auth/auth.d.ts +2 -2
- package/dist/auth/auth.js +24 -15
- package/dist/auth/llms.txt +12 -11
- package/dist/autocomplete/autocomplete.d.ts +19 -6
- package/dist/autocomplete/autocomplete.js +32 -11
- package/dist/autocomplete/llms.txt +19 -5
- package/dist/avatar/avatar.d.ts +6 -6
- package/dist/avatar/avatar.js +6 -5
- package/dist/avatar/llms.txt +10 -10
- package/dist/avatar-group/avatar-group.d.ts +4 -4
- package/dist/avatar-group/avatar-group.js +4 -3
- package/dist/avatar-group/llms.txt +8 -8
- package/dist/backdrop/backdrop.d.ts +7 -26
- package/dist/backdrop/backdrop.js +32 -27
- package/dist/backdrop/llms.txt +27 -27
- package/dist/badge/badge.d.ts +3 -3
- package/dist/badge/badge.js +1 -1
- package/dist/badge/llms.txt +11 -11
- package/dist/bottom-sheet/bottom-sheet.d.ts +8 -3
- package/dist/bottom-sheet/bottom-sheet.js +5 -4
- package/dist/bottom-sheet/llms.txt +11 -8
- package/dist/breadcrumb/breadcrumb.d.ts +8 -2
- package/dist/breadcrumb/breadcrumb.js +11 -3
- package/dist/breadcrumb/llms.txt +10 -2
- package/dist/button/button.d.ts +3 -3
- package/dist/button/button.js +10 -9
- package/dist/button/llms.txt +27 -19
- package/dist/button-group/button-group.d.ts +18 -5
- package/dist/button-group/button-group.js +54 -6
- package/dist/button-group/llms.txt +27 -18
- package/dist/card/card.d.ts +8 -8
- package/dist/card/card.js +10 -9
- package/dist/card/llms.txt +20 -20
- package/dist/carousel/carousel.d.ts +6 -6
- package/dist/carousel/carousel.js +8 -5
- package/dist/carousel/llms.txt +10 -10
- package/dist/charts/chart-legend.d.ts +3 -3
- package/dist/charts/chart-legend.js +2 -1
- package/dist/charts/chart-tooltip.d.ts +3 -3
- package/dist/charts/chart-tooltip.js +1 -1
- package/dist/charts/chart.d.ts +4 -3
- package/dist/charts/chart.js +18 -10
- package/dist/charts/llms.txt +10 -7
- package/dist/charts-entry/public-api.js +2 -2
- package/dist/chat/chat.d.ts +17 -10
- package/dist/chat/chat.js +77 -23
- package/dist/chat/llms.txt +39 -15
- package/dist/chat-composer/chat-composer.d.ts +20 -7
- package/dist/chat-composer/chat-composer.js +29 -7
- package/dist/chat-composer/llms.txt +20 -11
- package/dist/chat-dock/chat-dock.d.ts +11 -4
- package/dist/chat-dock/chat-dock.js +10 -6
- package/dist/chat-dock/llms.txt +15 -14
- package/dist/chat-entry/public-api.js +1 -1
- package/dist/chat-message/chat-message.d.ts +12 -5
- package/dist/chat-message/chat-message.js +19 -8
- package/dist/chat-message/llms.txt +16 -15
- package/dist/chat-typing/chat-typing.d.ts +2 -2
- package/dist/chat-typing/chat-typing.js +4 -3
- package/dist/chat-typing/llms.txt +6 -6
- package/dist/checkbox/checkbox.d.ts +13 -6
- package/dist/checkbox/checkbox.js +31 -5
- package/dist/checkbox/llms.txt +26 -11
- package/dist/chip/chip.d.ts +4 -4
- package/dist/chip/chip.js +3 -2
- package/dist/chip/llms.txt +11 -11
- package/dist/chips-input/chips-input.d.ts +6 -4
- package/dist/chips-input/chips-input.js +47 -12
- package/dist/chips-input/llms.txt +18 -8
- package/dist/clock/clock.d.ts +11 -6
- package/dist/clock/clock.js +38 -8
- package/dist/clock/llms.txt +12 -8
- package/dist/color-picker/color-picker.d.ts +9 -5
- package/dist/color-picker/color-picker.js +37 -18
- package/dist/color-picker/llms.txt +8 -5
- package/dist/confirm/confirm-container.d.ts +3 -3
- package/dist/confirm/confirm-container.js +6 -5
- package/dist/confirm/confirm-store.d.ts +4 -4
- package/dist/confirm/confirm-store.js +11 -5
- package/dist/confirm/llms.txt +8 -7
- package/dist/context-menu/context-menu.d.ts +1 -1
- package/dist/context-menu/context-menu.js +37 -14
- package/dist/context-menu/llms.txt +10 -7
- package/dist/data-table/data-table-types.d.ts +5 -5
- package/dist/data-table/data-table.d.ts +37 -5
- package/dist/data-table/data-table.js +426 -119
- package/dist/data-table/export-csv.d.ts +3 -3
- package/dist/data-table/export-csv.js +8 -10
- package/dist/data-table/llms.txt +127 -79
- package/dist/data-view/data-view.d.ts +13 -5
- package/dist/data-view/data-view.js +68 -6
- package/dist/data-view/llms.txt +29 -10
- package/dist/date-range/date-range.d.ts +20 -8
- package/dist/date-range/date-range.js +86 -63
- package/dist/date-range/llms.txt +32 -18
- package/dist/datepicker/datepicker.d.ts +22 -8
- package/dist/datepicker/datepicker.js +103 -71
- package/dist/datepicker/llms.txt +36 -22
- package/dist/dialog/dialog.d.ts +4 -4
- package/dist/dialog/dialog.js +32 -11
- package/dist/dialog/llms.txt +13 -10
- package/dist/divider/divider.d.ts +7 -1
- package/dist/divider/divider.js +3 -2
- package/dist/divider/llms.txt +4 -3
- package/dist/drawer/drawer.d.ts +9 -4
- package/dist/drawer/drawer.js +5 -4
- package/dist/drawer/llms.txt +13 -10
- package/dist/empty/empty.d.ts +2 -2
- package/dist/empty/empty.js +1 -1
- package/dist/empty/llms.txt +9 -9
- package/dist/fab/fab.d.ts +1 -1
- package/dist/fab/fab.js +1 -1
- package/dist/fab/llms.txt +10 -6
- package/dist/fieldset/fieldset.d.ts +18 -4
- package/dist/fieldset/fieldset.js +12 -6
- package/dist/fieldset/llms.txt +26 -9
- package/dist/file-upload/file-upload.d.ts +8 -2
- package/dist/file-upload/file-upload.js +22 -11
- package/dist/file-upload/llms.txt +12 -9
- package/dist/form-field/form-field-context.d.ts +4 -4
- package/dist/form-field/form-field.d.ts +12 -4
- package/dist/form-field/form-field.js +27 -6
- package/dist/form-field/llms.txt +25 -11
- package/dist/galleria/galleria.d.ts +3 -3
- package/dist/galleria/galleria.js +9 -6
- package/dist/galleria/llms.txt +7 -7
- package/dist/grid/col.d.ts +4 -4
- package/dist/grid/col.js +2 -2
- package/dist/grid/flex.d.ts +3 -3
- package/dist/grid/flex.js +1 -1
- package/dist/grid/grid.d.ts +7 -7
- package/dist/grid/grid.js +3 -3
- package/dist/grid/layout.d.ts +2 -2
- package/dist/grid/layout.js +2 -2
- package/dist/grid/llms.txt +15 -15
- package/dist/grid-entry/public-api.js +1 -1
- package/dist/i18n/i18n-context.d.ts +6 -6
- package/dist/i18n/i18n-context.js +27 -5
- package/dist/icon/icon-registry.d.ts +3 -3
- package/dist/icon/icon-registry.js +3 -3
- package/dist/icon/icon.d.ts +4 -4
- package/dist/icon/icon.js +10 -7
- package/dist/icon/llms.txt +13 -13
- package/dist/icon-button/icon-button.d.ts +2 -2
- package/dist/icon-button/icon-button.js +1 -1
- package/dist/icon-button/llms.txt +9 -5
- package/dist/icons-entry/public-api.d.ts +2 -2
- package/dist/icons-entry/public-api.js +3 -3
- package/dist/image/image.js +5 -5
- package/dist/image/llms.txt +13 -13
- package/dist/input/input.d.ts +18 -5
- package/dist/input/input.js +22 -6
- package/dist/input/llms.txt +25 -11
- package/dist/input-mask/input-mask.d.ts +7 -2
- package/dist/input-mask/input-mask.js +17 -43
- package/dist/input-mask/llms.txt +8 -5
- package/dist/input-number/input-number.d.ts +11 -9
- package/dist/input-number/input-number.js +25 -21
- package/dist/input-number/llms.txt +17 -14
- package/dist/input-otp/input-otp.d.ts +18 -5
- package/dist/input-otp/input-otp.js +48 -24
- package/dist/input-otp/llms.txt +18 -7
- package/dist/internal/calendar-focus.d.ts +1 -1
- package/dist/internal/calendar-focus.js +3 -3
- package/dist/internal/cn.d.ts +1 -1
- package/dist/internal/mask.d.ts +14 -0
- package/dist/internal/mask.js +62 -0
- package/dist/internal/number-group.d.ts +22 -0
- package/dist/internal/number-group.js +53 -0
- package/dist/internal/option-key.d.ts +6 -0
- package/dist/internal/option-key.js +8 -0
- package/dist/internal/option-nav.d.ts +4 -4
- package/dist/internal/option-nav.js +5 -5
- package/dist/internal/overlay-container.js +1 -1
- package/dist/internal/overlay.d.ts +3 -3
- package/dist/internal/overlay.js +40 -10
- package/dist/internal/password-strength.d.ts +6 -0
- package/dist/internal/password-strength.js +74 -0
- package/dist/internal/roving.d.ts +2 -2
- package/dist/internal/roving.js +3 -3
- package/dist/internal/scroll-lock.d.ts +6 -0
- package/dist/internal/scroll-lock.js +35 -0
- package/dist/internal/slot-children.d.ts +13 -0
- package/dist/internal/slot-children.js +31 -0
- package/dist/internal/slot.d.ts +3 -3
- package/dist/internal/slot.js +2 -2
- package/dist/internal/step.d.ts +12 -0
- package/dist/internal/step.js +31 -0
- package/dist/internal/tween.d.ts +5 -5
- package/dist/internal/tween.js +7 -8
- package/dist/internal/types.d.ts +2 -2
- package/dist/internal/use-breakpoint.d.ts +2 -2
- package/dist/internal/use-breakpoint.js +4 -4
- package/dist/internal/use-controllable-state.d.ts +5 -0
- package/dist/internal/use-controllable-state.js +25 -4
- package/dist/internal/use-id.d.ts +2 -2
- package/dist/internal/use-id.js +2 -2
- package/dist/internal/use-modal-focus.d.ts +2 -1
- package/dist/internal/use-modal-focus.js +14 -3
- package/dist/knob/knob.d.ts +7 -4
- package/dist/knob/knob.js +27 -22
- package/dist/knob/llms.txt +18 -11
- package/dist/listbox/listbox.d.ts +8 -6
- package/dist/listbox/listbox.js +37 -17
- package/dist/listbox/llms.txt +12 -9
- package/dist/loader/llms.txt +56 -0
- package/dist/loader/loader.d.ts +49 -0
- package/dist/loader/loader.js +68 -0
- package/dist/map/llms.txt +30 -23
- package/dist/map/map-create-dialog.d.ts +4 -4
- package/dist/map/map-create-dialog.js +36 -28
- package/dist/map/map-hours-field.d.ts +4 -4
- package/dist/map/map-hours-field.js +8 -7
- package/dist/map/map-image-field.d.ts +2 -2
- package/dist/map/map-image-field.js +6 -5
- package/dist/map/map-legend.d.ts +4 -4
- package/dist/map/map-legend.js +3 -2
- package/dist/map/map-poi-card.d.ts +3 -3
- package/dist/map/map-poi-card.js +10 -9
- package/dist/map/map-search.d.ts +17 -6
- package/dist/map/map-search.js +70 -43
- package/dist/map/map.d.ts +25 -13
- package/dist/map/map.js +86 -57
- package/dist/map/ports.d.ts +9 -9
- package/dist/map/ports.js +6 -6
- package/dist/map-entry/public-api.js +2 -2
- package/dist/megamenu/llms.txt +18 -7
- package/dist/megamenu/megamenu.d.ts +12 -6
- package/dist/megamenu/megamenu.js +23 -14
- package/dist/mention/llms.txt +15 -15
- package/dist/mention/mention.d.ts +5 -5
- package/dist/mention/mention.js +2 -2
- package/dist/mention/mentions.d.ts +1 -1
- package/dist/mention/mentions.js +1 -1
- package/dist/menu/llms.txt +12 -12
- package/dist/menu/menu-item.d.ts +4 -4
- package/dist/menu/menu-keys.d.ts +2 -2
- package/dist/menu/menu-keys.js +5 -5
- package/dist/menu/menu-rows.js +1 -0
- package/dist/menu/menu.d.ts +2 -2
- package/dist/menu/menu.js +15 -8
- package/dist/menubar/llms.txt +19 -8
- package/dist/menubar/menubar.d.ts +11 -5
- package/dist/menubar/menubar.js +23 -11
- package/dist/meter-group/llms.txt +12 -12
- package/dist/meter-group/meter-group.d.ts +2 -2
- package/dist/meter-group/meter-group.js +2 -1
- package/dist/motion/motion-context.d.ts +22 -0
- package/dist/motion/motion-context.js +28 -0
- package/dist/order-list/llms.txt +24 -9
- package/dist/order-list/order-list.d.ts +12 -4
- package/dist/order-list/order-list.js +123 -25
- package/dist/paginator/llms.txt +8 -8
- package/dist/paginator/paginator.js +7 -4
- package/dist/panel/llms.txt +25 -13
- package/dist/panel/panel.d.ts +11 -3
- package/dist/panel/panel.js +12 -7
- package/dist/password/llms.txt +19 -7
- package/dist/password/password.d.ts +2 -2
- package/dist/password/password.js +27 -16
- package/dist/peek/llms.txt +11 -11
- package/dist/peek/peek.d.ts +6 -6
- package/dist/peek/peek.js +41 -19
- package/dist/pick-list/llms.txt +35 -12
- package/dist/pick-list/pick-list.d.ts +12 -4
- package/dist/pick-list/pick-list.js +128 -24
- package/dist/popover/llms.txt +13 -10
- package/dist/popover/popover.d.ts +6 -4
- package/dist/popover/popover.js +14 -7
- package/dist/progress/llms.txt +17 -17
- package/dist/progress/progress.d.ts +7 -7
- package/dist/progress/progress.js +7 -6
- package/dist/public-api.d.ts +16 -4
- package/dist/public-api.js +13 -7
- package/dist/radio-group/llms.txt +16 -6
- package/dist/radio-group/radio-group.d.ts +12 -3
- package/dist/radio-group/radio-group.js +23 -4
- package/dist/rating/llms.txt +20 -13
- package/dist/rating/rating-pointer.d.ts +16 -0
- package/dist/rating/rating-pointer.js +26 -0
- package/dist/rating/rating.d.ts +6 -6
- package/dist/rating/rating.js +77 -12
- package/dist/rich-text/lists.d.ts +2 -2
- package/dist/rich-text/lists.js +7 -7
- package/dist/rich-text/llms.txt +35 -12
- package/dist/rich-text/rich-text.d.ts +13 -14
- package/dist/rich-text/rich-text.js +311 -142
- package/dist/rich-text/sanitize.d.ts +11 -2
- package/dist/rich-text/sanitize.js +80 -32
- package/dist/rich-text/tables.d.ts +3 -3
- package/dist/rich-text/tables.js +3 -3
- package/dist/roadmap/llms.txt +23 -17
- package/dist/roadmap/roadmap.d.ts +6 -6
- package/dist/roadmap/roadmap.js +102 -25
- package/dist/roadmap-entry/public-api.js +2 -2
- package/dist/scroll-top/llms.txt +6 -6
- package/dist/scroll-top/scroll-top.d.ts +1 -1
- package/dist/scroll-top/scroll-top.js +2 -1
- package/dist/select/llms.txt +22 -12
- package/dist/select/select.d.ts +10 -8
- package/dist/select/select.js +87 -47
- package/dist/shared/types.d.ts +22 -1
- package/dist/shared/types.js +9 -1
- package/dist/sidenav/llms.txt +9 -9
- package/dist/sidenav/sidenav.d.ts +2 -3
- package/dist/sidenav/sidenav.js +5 -4
- package/dist/skeleton/llms.txt +3 -3
- package/dist/skeleton/skeleton.d.ts +1 -1
- package/dist/skeleton/skeleton.js +1 -1
- package/dist/slider/llms.txt +34 -12
- package/dist/slider/slider-drag.d.ts +26 -0
- package/dist/slider/slider-drag.js +79 -0
- package/dist/slider/slider.d.ts +8 -5
- package/dist/slider/slider.js +38 -8
- package/dist/speech/llms.txt +97 -0
- package/dist/speech/speech-button.d.ts +44 -0
- package/dist/speech/speech-button.js +86 -0
- package/dist/speech/speech-wave.d.ts +19 -0
- package/dist/speech/speech-wave.js +16 -0
- package/dist/speech/use-speech-recognition.d.ts +81 -0
- package/dist/speech/use-speech-recognition.js +179 -0
- package/dist/speed-dial/llms.txt +14 -8
- package/dist/speed-dial/speed-dial.d.ts +1 -1
- package/dist/speed-dial/speed-dial.js +3 -2
- package/dist/spinner/llms.txt +7 -7
- package/dist/spinner/spinner.d.ts +1 -1
- package/dist/spinner/spinner.js +2 -1
- package/dist/split-button/llms.txt +21 -15
- package/dist/split-button/split-button.d.ts +2 -2
- package/dist/split-button/split-button.js +13 -6
- package/dist/splitter/llms.txt +11 -11
- package/dist/splitter/splitter.d.ts +3 -3
- package/dist/splitter/splitter.js +25 -10
- package/dist/stepper/llms.txt +35 -13
- package/dist/stepper/stepper.d.ts +6 -6
- package/dist/stepper/stepper.js +60 -13
- package/dist/switch/llms.txt +15 -5
- package/dist/switch/switch.d.ts +10 -3
- package/dist/switch/switch.js +18 -4
- package/dist/switch-group/llms.txt +11 -8
- package/dist/switch-group/switch-group.d.ts +6 -4
- package/dist/switch-group/switch-group.js +9 -7
- package/dist/tabs/llms.txt +12 -9
- package/dist/tabs/tabs.d.ts +5 -5
- package/dist/tabs/tabs.js +36 -20
- package/dist/textarea/llms.txt +23 -12
- package/dist/textarea/textarea.d.ts +19 -6
- package/dist/textarea/textarea.js +22 -7
- package/dist/timeline/llms.txt +4 -4
- package/dist/timeline/timeline.d.ts +1 -1
- package/dist/timeline/timeline.js +1 -1
- package/dist/toast/llms.txt +50 -17
- package/dist/toast/toast-container.d.ts +9 -3
- package/dist/toast/toast-container.js +18 -9
- package/dist/toast/toast-store.d.ts +42 -2
- package/dist/toast/toast-store.js +36 -1
- package/dist/toolbar/llms.txt +7 -7
- package/dist/toolbar/toolbar.d.ts +3 -3
- package/dist/toolbar/toolbar.js +2 -2
- package/dist/tooltip/llms.txt +14 -12
- package/dist/tooltip/tooltip.d.ts +5 -4
- package/dist/tooltip/tooltip.js +100 -41
- package/dist/tree/llms.txt +25 -11
- package/dist/tree/tree-keys.d.ts +5 -5
- package/dist/tree/tree-keys.js +7 -7
- package/dist/tree/tree.d.ts +17 -5
- package/dist/tree/tree.js +62 -20
- package/dist/update/llms.txt +54 -0
- package/dist/update/update.d.ts +49 -0
- package/dist/update/update.js +82 -0
- package/package.json +18 -15
package/dist/charts/chart.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ComponentPropsWithRef } from 'react';
|
|
2
2
|
import { type KptChartConfig } from '@konce-pt/chart';
|
|
3
|
-
|
|
3
|
+
import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
4
|
+
export interface KptChartProps extends Omit<ComponentPropsWithRef<'div'>, 'children'>, KptI18nOverrides {
|
|
4
5
|
config: KptChartConfig;
|
|
5
6
|
/** Szerokość viewBoxa w jednostkach SVG; wykres skaluje się do kontenera. */
|
|
6
7
|
width?: number;
|
|
@@ -9,10 +10,10 @@ export interface KptChartProps extends Omit<ComponentPropsWithRef<'div'>, 'child
|
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
12
|
* Wykres SVG sterowany jednym obiektem `config`: line, bar, pie, doughnut, polarArea, radar.
|
|
12
|
-
* Cała geometria pochodzi z `@konce-pt/chart`
|
|
13
|
+
* Cała geometria pochodzi z `@konce-pt/chart` - paczki bez frameworka, wspólnej z portem
|
|
13
14
|
* Angulara; komponent renderuje wyłącznie SVG, bez manipulacji DOM.
|
|
14
15
|
*
|
|
15
16
|
* @example
|
|
16
17
|
* <KptChart config={{ type: 'line', labels: ['Sty', 'Lut'], series: [{ name: 'Sprzedaż', data: [12, 19] }] }} />
|
|
17
18
|
*/
|
|
18
|
-
export declare function KptChart({ config, width, height, className, style, ...rest }: Readonly<KptChartProps>): import("react").JSX.Element;
|
|
19
|
+
export declare function KptChart({ config, width, height, locale, dictionary, className, style, ...rest }: Readonly<KptChartProps>): import("react").JSX.Element;
|
package/dist/charts/chart.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { areaPath, bandScale, barLayout, extent, formatNumber, linePath, linearScale, niceScale, pieSlices, plotArea, polarSlices, polarToCartesian, polygonPath, radarGrid, radarPoints, radialArea, seriesColor, } from '@konce-pt/chart';
|
|
3
|
+
import { useId, useState } from 'react';
|
|
4
|
+
import { areaPath, bandScale, barLayout, chartAccessibleName, chartDataTable, extent, formatNumber, linePath, linearScale, niceScale, pieSlices, plotArea, polarSlices, polarToCartesian, polygonPath, radarGrid, radarPoints, radialArea, seriesColor, } from '@konce-pt/chart';
|
|
4
5
|
import { cn } from "../internal/cn.js";
|
|
6
|
+
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
5
7
|
import { KptChartLegend } from "./chart-legend.js";
|
|
6
8
|
import { KptChartTooltip } from "./chart-tooltip.js";
|
|
7
9
|
const VERTICAL_INSETS = { top: 12, right: 16, bottom: 28, left: 46 };
|
|
@@ -15,17 +17,23 @@ function styleFor(align) {
|
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
19
|
* Wykres SVG sterowany jednym obiektem `config`: line, bar, pie, doughnut, polarArea, radar.
|
|
18
|
-
* Cała geometria pochodzi z `@konce-pt/chart`
|
|
20
|
+
* Cała geometria pochodzi z `@konce-pt/chart` - paczki bez frameworka, wspólnej z portem
|
|
19
21
|
* Angulara; komponent renderuje wyłącznie SVG, bez manipulacji DOM.
|
|
20
22
|
*
|
|
21
23
|
* @example
|
|
22
24
|
* <KptChart config={{ type: 'line', labels: ['Sty', 'Lut'], series: [{ name: 'Sprzedaż', data: [12, 19] }] }} />
|
|
23
25
|
*/
|
|
24
|
-
export function KptChart({ config, width = 600, height = 360, className, style, ...rest }) {
|
|
26
|
+
export function KptChart({ config, width = 600, height = 360, locale, dictionary, className, style, ...rest }) {
|
|
27
|
+
const { t, locale: activeLocale } = useKptMessages({ locale, dictionary });
|
|
28
|
+
const descId = `${useId()}-desc`;
|
|
29
|
+
// Alternatywa tekstowa (WCAG 1.1.1): nazwa SVG (`ariaLabel` -> tytuł -> i18n) i dane w ukrytej
|
|
30
|
+
// wizualnie tabeli - dymek na najechanie jest dostępny tylko myszą.
|
|
31
|
+
const accessibleName = chartAccessibleName(config, t('chart.label'));
|
|
32
|
+
const dataTable = chartDataTable(config, activeLocale);
|
|
25
33
|
const [hidden, setHidden] = useState(new Set());
|
|
26
34
|
const [highlighted, setHighlighted] = useState(null);
|
|
27
35
|
const [tooltip, setTooltip] = useState(null);
|
|
28
|
-
/** Indeks kategorii pod kursorem
|
|
36
|
+
/** Indeks kategorii pod kursorem - prowadnica crosshair w wykresie liniowym. */
|
|
29
37
|
const [activeIndex, setActiveIndex] = useState(null);
|
|
30
38
|
const anim = {
|
|
31
39
|
enabled: config.animation?.enabled ?? true,
|
|
@@ -71,7 +79,7 @@ export function KptChart({ config, width = 600, height = 360, className, style,
|
|
|
71
79
|
next.add(key);
|
|
72
80
|
setHidden(next);
|
|
73
81
|
};
|
|
74
|
-
//
|
|
82
|
+
// -- Wykres liniowy --
|
|
75
83
|
const lineVm = (() => {
|
|
76
84
|
if (config.type !== 'line')
|
|
77
85
|
return null;
|
|
@@ -124,7 +132,7 @@ export function KptChart({ config, width = 600, height = 360, className, style,
|
|
|
124
132
|
} })] }, idx)))] }, key));
|
|
125
133
|
})] }));
|
|
126
134
|
})();
|
|
127
|
-
//
|
|
135
|
+
// -- Wykres słupkowy --
|
|
128
136
|
const barVm = (() => {
|
|
129
137
|
if (config.type !== 'bar')
|
|
130
138
|
return null;
|
|
@@ -159,7 +167,7 @@ export function KptChart({ config, width = 600, height = 360, className, style,
|
|
|
159
167
|
return (_jsx("path", { className: cn('kpt-chart__bar', dim(key) && 'kpt-chart__series--dim'), d: b.path, style: { fill: color, ['--kpt-chart-i']: order }, onPointerEnter: () => showTip(tipX, tipY, names[b.seriesIndex], config.labels[b.categoryIndex] ?? '', b.value, color), onPointerLeave: hideTip }, `${key}#${order}`));
|
|
160
168
|
}) })] }));
|
|
161
169
|
})();
|
|
162
|
-
//
|
|
170
|
+
// -- Pie / doughnut / polar area --
|
|
163
171
|
const pieVm = (() => {
|
|
164
172
|
if (!isPieLike)
|
|
165
173
|
return null;
|
|
@@ -184,7 +192,7 @@ export function KptChart({ config, width = 600, height = 360, className, style,
|
|
|
184
192
|
return (_jsx("path", { className: cn('kpt-chart__slice', dim(key) && 'kpt-chart__series--dim'), d: slice.path, style: { fill: entry.color, ['--kpt-chart-i']: k }, onPointerEnter: () => showTip(tip.x, tip.y, entry.label, '', entry.value, entry.color), onPointerLeave: hideTip }, key));
|
|
185
193
|
}) }));
|
|
186
194
|
})();
|
|
187
|
-
//
|
|
195
|
+
// -- Radar --
|
|
188
196
|
const radarVm = (() => {
|
|
189
197
|
if (config.type !== 'radar')
|
|
190
198
|
return null;
|
|
@@ -227,5 +235,5 @@ export function KptChart({ config, width = 600, height = 360, className, style,
|
|
|
227
235
|
fontWeight: config.subtitle.font?.weight,
|
|
228
236
|
paddingTop: config.subtitle.padding?.top,
|
|
229
237
|
paddingBottom: config.subtitle.padding?.bottom,
|
|
230
|
-
}, children: config.subtitle.text })) : null, _jsxs("div", { className: "kpt-chart__body", children: [_jsxs("div", { className: "kpt-chart__canvas", children: [_jsxs("svg", { className: "kpt-chart__svg", viewBox: `0 0 ${width} ${height}`, role: "img", preserveAspectRatio: "xMidYMid meet", children: [lineVm, barVm, radarVm, pieVm] }), _jsx(KptChartTooltip, { state: tooltip })] }), legendOpts.display ? (_jsx(KptChartLegend, { items: legendItems, position: legendOpts.position, align: legendOpts.align, pointStyle: legendOpts.pointStyle, title: legendOpts.title, onToggle: toggle, onHighlight: setHighlighted })) : null] })] }) }));
|
|
238
|
+
}, children: config.subtitle.text })) : null, _jsxs("div", { className: "kpt-chart__body", children: [_jsxs("div", { className: "kpt-chart__canvas", children: [_jsxs("svg", { className: "kpt-chart__svg", viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": accessibleName, "aria-describedby": config.description ? descId : undefined, preserveAspectRatio: "xMidYMid meet", children: [lineVm, barVm, radarVm, pieVm] }), config.description ? (_jsx("p", { className: "kpt-chart__sr", id: descId, children: config.description })) : null, _jsxs("table", { className: "kpt-chart__sr", children: [_jsxs("caption", { children: [t('chart.dataTable'), ": ", accessibleName] }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: t('chart.category') }), dataTable.columns.map((col, i) => (_jsx("th", { scope: "col", children: col }, i)))] }) }), _jsx("tbody", { children: dataTable.rows.map((row, i) => (_jsxs("tr", { children: [_jsx("th", { scope: "row", children: row.label }), row.values.map((value, j) => (_jsx("td", { children: value }, j)))] }, i))) })] }), _jsx(KptChartTooltip, { state: tooltip })] }), legendOpts.display ? (_jsx(KptChartLegend, { items: legendItems, position: legendOpts.position, align: legendOpts.align, pointStyle: legendOpts.pointStyle, title: legendOpts.title, onToggle: toggle, onHighlight: setHighlighted })) : null] })] }) }));
|
|
231
239
|
}
|
package/dist/charts/llms.txt
CHANGED
|
@@ -8,22 +8,22 @@ and not every app needs them.
|
|
|
8
8
|
|
|
9
9
|
## Props
|
|
10
10
|
- `config`: `KptChartConfig` (required)
|
|
11
|
-
- `width`, `height`
|
|
11
|
+
- `width`, `height` - the viewBox in SVG units (600 x 360); the chart scales to its container
|
|
12
12
|
|
|
13
13
|
The whole drawing lives in that coordinate system, TYPOGRAPHY INCLUDED: the axis labels are set in
|
|
14
14
|
`font-size: 11px`, but inside an SVG that means 11 user units, not 11 device pixels. Render a
|
|
15
15
|
600-unit chart in a 300px column and the labels come out at roughly half size. `width`/`height` are
|
|
16
|
-
therefore not just an aspect ratio
|
|
16
|
+
therefore not just an aspect ratio - they are the text scale. In a narrow container shrink them
|
|
17
17
|
proportionally (`width={300} height={180}`) instead of letting a 600-unit chart squeeze itself.
|
|
18
18
|
- `className`, `ref` and every other `<div>` prop go to the host
|
|
19
19
|
|
|
20
20
|
## The config is the API
|
|
21
21
|
`{ type, labels, series, points?, area?, interpolation?, orientation?, borderRadius?, innerRadius?,
|
|
22
|
-
crosshair?, tooltip?, legend?, title?, subtitle?, animation? }`
|
|
22
|
+
crosshair?, tooltip?, legend?, title?, subtitle?, animation?, ariaLabel?, description? }` - the same shape the Angular port
|
|
23
23
|
takes, because both read it from `@konce-pt/chart`.
|
|
24
24
|
|
|
25
25
|
## The geometry lives in a package
|
|
26
|
-
Scales, paths, bar layout and arcs come from `@konce-pt/chart`
|
|
26
|
+
Scales, paths, bar layout and arcs come from `@konce-pt/chart` - pure functions with `node --test`
|
|
27
27
|
coverage, shared with the Angular port. The component only turns them into SVG elements; there is
|
|
28
28
|
no DOM manipulation and no canvas.
|
|
29
29
|
|
|
@@ -32,7 +32,7 @@ A 4px point is not something a pointer can reliably hit, so each one is paired w
|
|
|
32
32
|
12px circle that carries the events. The visible point only reacts to the state.
|
|
33
33
|
|
|
34
34
|
## Interaction is local state
|
|
35
|
-
Hidden series, the highlighted one, the tooltip and the active category are `useState`
|
|
35
|
+
Hidden series, the highlighted one, the tooltip and the active category are `useState` - the config
|
|
36
36
|
stays a plain object the caller owns, and nothing is written back into it.
|
|
37
37
|
|
|
38
38
|
## Examples
|
|
@@ -53,5 +53,8 @@ stays a plain object the caller owns, and nothing is written back into it.
|
|
|
53
53
|
`KPT_CHART_PALETTE` or `series.color`.
|
|
54
54
|
|
|
55
55
|
## Accessibility
|
|
56
|
-
The `<svg>`
|
|
57
|
-
from the
|
|
56
|
+
The `<svg>` is `role="img"` with a name: `config.ariaLabel`, else the title text, else `chart.label`
|
|
57
|
+
from i18n. `config.description` (one sentence with the takeaway) is tied to it through
|
|
58
|
+
`aria-describedby`. The data itself sits in a visually hidden `<table>` (categories in rows, series in
|
|
59
|
+
columns, numbers in the active language), so a screen reader can walk the values - the tooltip is
|
|
60
|
+
pointer-only. The legend is a list of real buttons, so series can be toggled from the keyboard.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* @konce-pt/react/charts
|
|
2
|
+
* @konce-pt/react/charts - wykresy SVG. Osobny subpath, bo geometria i style wykresów są
|
|
3
3
|
* ciężkie względem rdzenia biblioteki i nie każda aplikacja ich potrzebuje.
|
|
4
4
|
*/
|
|
5
5
|
export { KptChart } from "../charts/chart.js";
|
|
6
|
-
// Rdzeń obliczeniowy
|
|
6
|
+
// Rdzeń obliczeniowy - przydatny do własnych rozszerzeń i renderowania po stronie serwera.
|
|
7
7
|
export { KPT_CHART_PALETTE, seriesColor, linePath, areaPath, pieSlices, polarSlices, barLayout, radarGrid, radarPoints, niceScale, } from '@konce-pt/chart';
|
package/dist/chat/chat.d.ts
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import { type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
2
|
+
import { type KptEnterMotion } from '@konce-pt/motion';
|
|
2
3
|
import type { KptChatAuthor, KptChatMessage as KptChatMessageModel, KptChatMessageRow, KptChatReactionOption, KptChatReplyRef } from '@konce-pt/chat';
|
|
3
4
|
import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
4
|
-
/** Wybór reakcji na wiadomości
|
|
5
|
+
/** Wybór reakcji na wiadomości - komponent mówi, w co kliknięto, dopisanie należy do aplikacji. */
|
|
5
6
|
export interface KptChatReactEvent<T = unknown> {
|
|
6
7
|
message: KptChatMessageModel<T>;
|
|
7
8
|
emoji: string;
|
|
8
9
|
}
|
|
9
10
|
export interface KptChatProps<T = unknown> extends Omit<ComponentPropsWithRef<'div'>, 'children'>, KptI18nOverrides {
|
|
10
|
-
/** Wiadomości w kolejności chronologicznej
|
|
11
|
+
/** Wiadomości w kolejności chronologicznej - komponent ich nie sortuje. */
|
|
11
12
|
messages?: readonly KptChatMessageModel<T>[];
|
|
12
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Ruch pojawiania się (nowe wiadomości, reakcje, status): `spring` - wyrasta z miejsca, z którego przychodzi, na sprężynie;
|
|
15
|
+
* `fade` - tylko się przenika; `none` - bez ruchu. Bez wartości bierze `enter` z `KptMotionProvider`
|
|
16
|
+
* (domyślnie `spring`); `enabled={false}` i systemowe "ogranicz ruch" wyłączają go zawsze.
|
|
17
|
+
*/
|
|
18
|
+
enterMotion?: KptEnterMotion;
|
|
19
|
+
/** `id` nadawcy uznawanego za "mnie": jego wiadomości idą na prawo i mają status. */
|
|
13
20
|
currentUser?: string;
|
|
14
21
|
/** Przerwa łamiąca grupę wiadomości jednego nadawcy. */
|
|
15
22
|
groupGapMs?: number;
|
|
16
|
-
/** `id` pierwszej nieprzeczytanej wiadomości
|
|
23
|
+
/** `id` pierwszej nieprzeczytanej wiadomości - nad nią stanie dzielnik. */
|
|
17
24
|
unreadFrom?: string | null;
|
|
18
25
|
/** Brak połączenia: pasek u góry listy z liczbą wiadomości czekających na wysłanie. */
|
|
19
26
|
offline?: boolean;
|
|
@@ -31,23 +38,23 @@ export interface KptChatProps<T = unknown> extends Omit<ComponentPropsWithRef<'d
|
|
|
31
38
|
onReply?: (message: KptChatMessageModel<T>) => void;
|
|
32
39
|
onReact?: (event: KptChatReactEvent<T>) => void;
|
|
33
40
|
onQuoted?: (quote: KptChatReplyRef) => void;
|
|
34
|
-
/** Przewinięcie na sam szczyt
|
|
41
|
+
/** Przewinięcie na sam szczyt - moment na dociągnięcie starszych wiadomości. */
|
|
35
42
|
onLoadMore?: () => void;
|
|
36
|
-
/** Szablon treści bąbla
|
|
43
|
+
/** Szablon treści bąbla - odpowiednik `<ng-template let-message>` z Angulara. */
|
|
37
44
|
renderMessage?: (message: KptChatMessageModel<T>, row: KptChatMessageRow<T>) => ReactNode;
|
|
38
45
|
}
|
|
39
46
|
/**
|
|
40
|
-
* Lista rozmowy
|
|
47
|
+
* Lista rozmowy - grupuje wiadomości, wstawia separatory dni i dzielnik nieprzeczytanych,
|
|
41
48
|
* trzyma widok przy dole i pokazuje pasek offline z liczbą wiadomości czekających na wysłanie.
|
|
42
49
|
*
|
|
43
50
|
* Sama logika wierszy mieszka w `@konce-pt/chat` (`buildChatRows`), więc port Angulara liczy ją
|
|
44
51
|
* tak samo. Komponent nie ma nic wspólnego z transportem: wiadomości dostaje, a `onRetry`
|
|
45
|
-
* i `onLoadMore` tylko zgłasza
|
|
52
|
+
* i `onLoadMore` tylko zgłasza - ponowieniem wysyłki i dociąganiem historii zajmuje się aplikacja.
|
|
46
53
|
*
|
|
47
|
-
* Kompozytor (`KptChatComposer`) jest osobnym komponentem i stoi obok listy
|
|
54
|
+
* Kompozytor (`KptChatComposer`) jest osobnym komponentem i stoi obok listy - dzięki temu
|
|
48
55
|
* czat bez pola wpisywania (podgląd, archiwum) nie wozi go ze sobą.
|
|
49
56
|
*
|
|
50
57
|
* @example
|
|
51
58
|
* <KptChat messages={messages} currentUser="me" typing={typing} onRetry={resend} />
|
|
52
59
|
*/
|
|
53
|
-
export declare function KptChat<T = unknown>({ messages, currentUser, groupGapMs, unreadFrom, offline, typing, autoScroll, actions, reactionOptions, emptyLabel, onRetry, onReply, onReact, onQuoted, onLoadMore, renderMessage, locale, dictionary, className, ...rest }: Readonly<KptChatProps<T>>): import("react").JSX.Element;
|
|
60
|
+
export declare function KptChat<T = unknown>({ messages, currentUser, groupGapMs, unreadFrom, offline, typing, autoScroll, actions, reactionOptions, emptyLabel, enterMotion, onRetry, onReply, onReact, onQuoted, onLoadMore, renderMessage, locale, dictionary, className, ...rest }: Readonly<KptChatProps<T>>): import("react").JSX.Element;
|
package/dist/chat/chat.js
CHANGED
|
@@ -1,34 +1,37 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
3
|
+
import { useCallback, useEffect, useEffectEvent, useLayoutEffect, useRef, useState } from 'react';
|
|
3
4
|
import { KPT_CHAT_GROUP_GAP_MS, KPT_CHAT_REACTIONS, buildChatRows, chatDayIndicator, pendingCount } from '@konce-pt/chat';
|
|
5
|
+
import { playEnterMotion, resolveEnterMotion } from '@konce-pt/motion';
|
|
4
6
|
import { cn } from "../internal/cn.js";
|
|
5
7
|
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
6
8
|
import { KptIcon } from "../icon/icon.js";
|
|
7
9
|
import { KptChatMessage } from "../chat-message/chat-message.js";
|
|
8
10
|
import { KptChatTyping } from "../chat-typing/chat-typing.js";
|
|
11
|
+
import { useKptMotion } from "../motion/motion-context.js";
|
|
9
12
|
/** Odległość od dołu (px), przy której listę uznajemy jeszcze za przypiętą. */
|
|
10
13
|
const PIN_THRESHOLD = 48;
|
|
11
14
|
/**
|
|
12
15
|
* Wiersze, które nie mogą znaleźć się pod pływającą pigułką dnia: separatory i komunikaty
|
|
13
|
-
* systemowe, czyli wszystko wyśrodkowane, co czyta się jak jej bliźniak. Bąble są poza listą
|
|
16
|
+
* systemowe, czyli wszystko wyśrodkowane, co czyta się jak jej bliźniak. Bąble są poza listą -
|
|
14
17
|
* pigułka nad wypowiedzią to normalny obrazek czatu.
|
|
15
18
|
*/
|
|
16
19
|
const BLOCKING_ROWS = '.kpt-chat__date, .kpt-chat__unread, .kpt-chat-message__system';
|
|
17
20
|
/**
|
|
18
|
-
* Lista rozmowy
|
|
21
|
+
* Lista rozmowy - grupuje wiadomości, wstawia separatory dni i dzielnik nieprzeczytanych,
|
|
19
22
|
* trzyma widok przy dole i pokazuje pasek offline z liczbą wiadomości czekających na wysłanie.
|
|
20
23
|
*
|
|
21
24
|
* Sama logika wierszy mieszka w `@konce-pt/chat` (`buildChatRows`), więc port Angulara liczy ją
|
|
22
25
|
* tak samo. Komponent nie ma nic wspólnego z transportem: wiadomości dostaje, a `onRetry`
|
|
23
|
-
* i `onLoadMore` tylko zgłasza
|
|
26
|
+
* i `onLoadMore` tylko zgłasza - ponowieniem wysyłki i dociąganiem historii zajmuje się aplikacja.
|
|
24
27
|
*
|
|
25
|
-
* Kompozytor (`KptChatComposer`) jest osobnym komponentem i stoi obok listy
|
|
28
|
+
* Kompozytor (`KptChatComposer`) jest osobnym komponentem i stoi obok listy - dzięki temu
|
|
26
29
|
* czat bez pola wpisywania (podgląd, archiwum) nie wozi go ze sobą.
|
|
27
30
|
*
|
|
28
31
|
* @example
|
|
29
32
|
* <KptChat messages={messages} currentUser="me" typing={typing} onRetry={resend} />
|
|
30
33
|
*/
|
|
31
|
-
export function KptChat({ messages = [], currentUser = '', groupGapMs = KPT_CHAT_GROUP_GAP_MS, unreadFrom = null, offline = false, typing = [], autoScroll = true, actions = false, reactionOptions = KPT_CHAT_REACTIONS, emptyLabel = '', onRetry, onReply, onReact, onQuoted, onLoadMore, renderMessage, locale, dictionary, className, ...rest }) {
|
|
34
|
+
export function KptChat({ messages = [], currentUser = '', groupGapMs = KPT_CHAT_GROUP_GAP_MS, unreadFrom = null, offline = false, typing = [], autoScroll = true, actions = false, reactionOptions = KPT_CHAT_REACTIONS, emptyLabel = '', enterMotion, onRetry, onReply, onReact, onQuoted, onLoadMore, renderMessage, locale, dictionary, className, ...rest }) {
|
|
32
35
|
const { t, locale: activeLocale } = useKptMessages({ locale, dictionary });
|
|
33
36
|
const viewportRef = useRef(null);
|
|
34
37
|
const dayRef = useRef(null);
|
|
@@ -36,16 +39,17 @@ export function KptChat({ messages = [], currentUser = '', groupGapMs = KPT_CHAT
|
|
|
36
39
|
const [pinned, setPinned] = useState(true);
|
|
37
40
|
/** Ile wiadomości przyszło, odkąd użytkownik odjechał w górę. */
|
|
38
41
|
const [newCount, setNewCount] = useState(0);
|
|
39
|
-
/** Tekst pływającej pigułki dnia
|
|
42
|
+
/** Tekst pływającej pigułki dnia - zostaje po zgaszeniu, żeby jej pas nie zmieniał wysokości. */
|
|
40
43
|
const [dayLabel, setDayLabel] = useState('');
|
|
41
44
|
/** Czy pigułka dnia jest widoczna. */
|
|
42
45
|
const [dayVisible, setDayVisible] = useState(false);
|
|
43
46
|
const lastCount = useRef(0);
|
|
44
47
|
const wasAtTop = useRef(false);
|
|
45
48
|
const rows = buildChatRows(messages, { currentUserId: currentUser, gapMs: groupGapMs, unreadFrom });
|
|
49
|
+
const motion = resolveEnterMotion(enterMotion, useKptMotion());
|
|
46
50
|
const pending = pendingCount(messages);
|
|
47
51
|
/**
|
|
48
|
-
* Ustawia tekst pływającej pigułki dnia
|
|
52
|
+
* Ustawia tekst pływającej pigułki dnia - co ma na niej być, liczy `chatDayIndicator`
|
|
49
53
|
* z `@konce-pt/chat`, tutaj zostaje czytanie prostokątów i przepisanie etykiety.
|
|
50
54
|
*
|
|
51
55
|
* Wszystkie pomiary idą przed zapisem stanu, więc przeglądarka przelicza układ raz
|
|
@@ -77,24 +81,65 @@ export function KptChat({ messages = [], currentUser = '', groupGapMs = KPT_CHAT
|
|
|
77
81
|
const reduced = globalThis.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;
|
|
78
82
|
element.scrollTo({ top: element.scrollHeight, behavior: behavior ?? (reduced ? 'auto' : 'smooth') });
|
|
79
83
|
};
|
|
80
|
-
|
|
84
|
+
const firstIdRef = useRef(null);
|
|
85
|
+
const prevScrollHeight = useRef(0);
|
|
86
|
+
const dayFrame = useRef(0);
|
|
87
|
+
// Wartości czytane w efekcie listy, ale nieuruchamiające go - przez zdarzenia efektu.
|
|
88
|
+
const autoScrollOnNew = useEffectEvent(() => autoScroll);
|
|
89
|
+
const pinnedNow = useEffectEvent(() => pinned);
|
|
90
|
+
const bumpNewCount = useEffectEvent((added) => setNewCount((value) => value + added));
|
|
91
|
+
/**
|
|
92
|
+
* Wejście wiadomości doklejonych na dole: własna wyrasta od pola pisania, cudza wchodzi od strony
|
|
93
|
+
* nadawcy. Pierwsze wejście i starsze doczytane na górze się nie ruszają - to nie są nowości.
|
|
94
|
+
*/
|
|
95
|
+
const playEntered = useEffectEvent((viewport, added) => {
|
|
96
|
+
if (motion === 'none')
|
|
97
|
+
return;
|
|
98
|
+
const hosts = viewport.querySelectorAll(':scope > .kpt-chat-message-host');
|
|
99
|
+
const messageRows = rows.filter((row) => row.kind === 'message');
|
|
100
|
+
const count = Math.min(added, 5, hosts.length);
|
|
101
|
+
for (let k = 0; k < count; k++) {
|
|
102
|
+
const index = hosts.length - count + k;
|
|
103
|
+
const row = messageRows[index];
|
|
104
|
+
const host = hosts[index];
|
|
105
|
+
if (!row || !host || row.kind !== 'message')
|
|
106
|
+
continue;
|
|
107
|
+
playEnterMotion(host, motion, row.own ? 'below' : 'start', k * 40);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
// Dosunięcie liczone po ułożeniu, nie po malowaniu - inaczej widać skok listy.
|
|
81
111
|
useLayoutEffect(() => {
|
|
82
112
|
if (!viewportRef.current)
|
|
83
113
|
return;
|
|
114
|
+
const element = viewportRef.current;
|
|
84
115
|
const count = messages.length;
|
|
85
|
-
const
|
|
116
|
+
const added = count - lastCount.current;
|
|
86
117
|
const first = lastCount.current === 0;
|
|
118
|
+
const firstId = messages[0]?.id ?? null;
|
|
119
|
+
// Starsze wiadomości doklejone na górze (`onLoadMore`) - nie są nowe, a widok ma zostać w miejscu.
|
|
120
|
+
const prepended = !first && added > 0 && firstId !== firstIdRef.current;
|
|
87
121
|
lastCount.current = count;
|
|
88
|
-
|
|
122
|
+
firstIdRef.current = firstId;
|
|
123
|
+
if (prepended) {
|
|
124
|
+
// Przeglądarki z `overflow-anchor` kotwiczą same; Safari go nie ma i bez tego lista skacze.
|
|
125
|
+
if (!globalThis.CSS?.supports('overflow-anchor', 'auto'))
|
|
126
|
+
element.scrollTop += element.scrollHeight - prevScrollHeight.current;
|
|
127
|
+
prevScrollHeight.current = element.scrollHeight;
|
|
89
128
|
return;
|
|
90
|
-
|
|
91
|
-
|
|
129
|
+
}
|
|
130
|
+
prevScrollHeight.current = element.scrollHeight;
|
|
131
|
+
if (added <= 0)
|
|
132
|
+
return;
|
|
133
|
+
if (!first)
|
|
134
|
+
playEntered(element, added);
|
|
135
|
+
// Pierwsze wejście zawsze ląduje na dole - rozmowę czyta się od końca.
|
|
136
|
+
if (first || (autoScrollOnNew() && pinnedNow()))
|
|
92
137
|
scrollToBottom(first ? 'auto' : undefined);
|
|
138
|
+
// Tyle, ile naprawdę przyszło - paczka pięciu wiadomości to "5 nowych", nie "1".
|
|
93
139
|
else
|
|
94
|
-
|
|
95
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
140
|
+
bumpNewCount(added);
|
|
96
141
|
}, [messages]);
|
|
97
|
-
// Po każdej zmianie listy wiersze stoją gdzie indziej
|
|
142
|
+
// Po każdej zmianie listy wiersze stoją gdzie indziej - pigułkę trzeba przeliczyć, inaczej
|
|
98
143
|
// pokazywałaby dzień sprzed dojścia nowej wiadomości.
|
|
99
144
|
useEffect(() => {
|
|
100
145
|
syncDay();
|
|
@@ -114,13 +159,19 @@ export function KptChat({ messages = [], currentUser = '', groupGapMs = KPT_CHAT
|
|
|
114
159
|
setPinned(atBottom);
|
|
115
160
|
if (atBottom)
|
|
116
161
|
setNewCount(0);
|
|
117
|
-
// `onLoadMore` tylko na wejściu w strefę szczytu
|
|
162
|
+
// `onLoadMore` tylko na wejściu w strefę szczytu - przy każdym zdarzeniu scroll
|
|
118
163
|
// aplikacja dostawałaby dziesiątki żądań na jedno przewinięcie.
|
|
119
164
|
const atTop = element.scrollTop < PIN_THRESHOLD;
|
|
120
165
|
if (atTop && !wasAtTop.current)
|
|
121
166
|
onLoadMore?.();
|
|
122
167
|
wasAtTop.current = atTop;
|
|
123
|
-
|
|
168
|
+
// Pomiary pigułki raz na klatkę, nie przy każdym zdarzeniu `scroll` (wymuszony układ).
|
|
169
|
+
if (dayFrame.current)
|
|
170
|
+
return;
|
|
171
|
+
dayFrame.current = requestAnimationFrame(() => {
|
|
172
|
+
dayFrame.current = 0;
|
|
173
|
+
syncDay();
|
|
174
|
+
});
|
|
124
175
|
};
|
|
125
176
|
const jumpToLatest = () => {
|
|
126
177
|
setPinned(true);
|
|
@@ -128,8 +179,8 @@ export function KptChat({ messages = [], currentUser = '', groupGapMs = KPT_CHAT
|
|
|
128
179
|
scrollToBottom();
|
|
129
180
|
};
|
|
130
181
|
/**
|
|
131
|
-
* Etykieta separatora dnia. Rdzeń zwraca rodzaj, słownik daje
|
|
132
|
-
* a nazwę dnia i pełną datę
|
|
182
|
+
* Etykieta separatora dnia. Rdzeń zwraca rodzaj, słownik daje "dziś"/"wczoraj",
|
|
183
|
+
* a nazwę dnia i pełną datę - `Intl`, żeby nie trzymać w słowniku kalendarza.
|
|
133
184
|
*/
|
|
134
185
|
const dateText = (label) => {
|
|
135
186
|
switch (label.kind) {
|
|
@@ -147,7 +198,10 @@ export function KptChat({ messages = [], currentUser = '', groupGapMs = KPT_CHAT
|
|
|
147
198
|
}).format(label.date);
|
|
148
199
|
}
|
|
149
200
|
};
|
|
150
|
-
return (_jsxs("div", { className: cn('kpt-chat-host', className), ...rest, children: [offline ? (_jsxs("p", { className: "kpt-chat__offline", role: "status", children: [_jsx(KptIcon, { name: "alert-triangle" }), _jsx("span", { children: t('chat.offline') }), pending ? (_jsx("span", { className: "kpt-chat__offline-count", children: t('chat.pending', { count: pending }) })) : null] })) : null, _jsxs("div", { className: "kpt-chat__body", children: [_jsxs("div", { ref: viewportRef, className: "kpt-chat__viewport", role: "log", "aria-live": "polite", "aria-relevant": "additions",
|
|
201
|
+
return (_jsxs("div", { className: cn('kpt-chat-host', className), ...rest, children: [offline ? (_jsxs("p", { className: "kpt-chat__offline", role: "status", children: [_jsx(KptIcon, { name: "alert-triangle" }), _jsx("span", { children: t('chat.offline') }), pending ? (_jsx("span", { className: "kpt-chat__offline-count", children: t('chat.pending', { count: pending }) })) : null] })) : null, _jsxs("div", { className: "kpt-chat__body", children: [_jsxs("div", { ref: viewportRef, className: "kpt-chat__viewport", role: "log", "aria-live": "polite", "aria-relevant": "additions",
|
|
202
|
+
// Przewijana historia musi być osiągalna z klawiatury także bez fokusowalnych bąbli.
|
|
203
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- przewijany region musi być osiągalny z klawiatury (WCAG 2.1.1) - role="log" nie jest interaktywna, przewijanie tak
|
|
204
|
+
tabIndex: 0, "aria-label": t('chat.history'), onScroll: (event) => onScroll(event.currentTarget), children: [rows.length === 0 ? (_jsx("p", { className: "kpt-chat__empty", children: emptyLabel || t('chat.empty') })) : null, rows.map((row) => {
|
|
151
205
|
if (row.kind === 'date') {
|
|
152
206
|
const label = dateText(row.label);
|
|
153
207
|
return (_jsx("p", { className: "kpt-chat__date", role: "separator", "aria-label": label, children: label }, row.key));
|
|
@@ -155,6 +209,6 @@ export function KptChat({ messages = [], currentUser = '', groupGapMs = KPT_CHAT
|
|
|
155
209
|
if (row.kind === 'unread') {
|
|
156
210
|
return (_jsx("p", { className: "kpt-chat__unread", role: "separator", "aria-label": t('chat.newMessages', { count: row.count }), children: _jsx("span", { children: t('chat.unread') }) }, row.key));
|
|
157
211
|
}
|
|
158
|
-
return (_jsx(KptChatMessage, { message: row.message, text: renderMessage ? '' : null, align: row.own ? 'end' : 'start', position: row.position, showAuthor: row.showAuthor, showAvatar: row.showAvatar, showMeta: row.showMeta, actions: actions, reactionOptions: reactionOptions, locale: locale, dictionary: dictionary, onRetry: () => onRetry?.(row.message), onReply: () => onReply?.(row.message), onReact: (emoji) => onReact?.({ message: row.message, emoji }), onQuoted: (quote) => onQuoted?.(quote), children: renderMessage ? renderMessage(row.message, row) : null }, row.key));
|
|
159
|
-
}), typing.length ? _jsx(KptChatTyping, { authors: typing, locale: locale, dictionary: dictionary }) : null] }), _jsx("p", { ref: dayRef, className: "kpt-chat__day", "aria-hidden": "true", "data-hidden": dayVisible ? undefined : '', children: dayLabel }), newCount ? (_jsxs("button", { type: "button", className: "kpt-chat__jump", onClick: jumpToLatest, children: [_jsx(KptIcon, { name: "arrow-down" }), t('chat.newMessages', { count: newCount })] })) : null] })] }));
|
|
212
|
+
return (_jsx(KptChatMessage, { message: row.message, text: renderMessage ? '' : null, align: row.own ? 'end' : 'start', position: row.position, showAuthor: row.showAuthor, showAvatar: row.showAvatar, showMeta: row.showMeta, actions: actions, reactionOptions: reactionOptions, enterMotion: motion, locale: locale, dictionary: dictionary, onRetry: () => onRetry?.(row.message), onReply: () => onReply?.(row.message), onReact: (emoji) => onReact?.({ message: row.message, emoji }), onQuoted: (quote) => onQuoted?.(quote), children: renderMessage ? renderMessage(row.message, row) : null }, row.key));
|
|
213
|
+
}), typing.length ? (_jsx("div", { "aria-live": "off", children: _jsx(KptChatTyping, { authors: typing, locale: locale, dictionary: dictionary }) })) : null] }), _jsx("p", { ref: dayRef, className: "kpt-chat__day", "aria-hidden": "true", "data-hidden": dayVisible ? undefined : '', children: dayLabel }), newCount ? (_jsxs("button", { type: "button", className: "kpt-chat__jump", onClick: jumpToLatest, children: [_jsx(KptIcon, { name: "arrow-down" }), t('chat.newMessages', { count: newCount })] })) : null] })] }));
|
|
160
214
|
}
|
package/dist/chat/llms.txt
CHANGED
|
@@ -6,13 +6,13 @@ Import: `import { KptChat } from '@konce-pt/react/chat';`
|
|
|
6
6
|
|
|
7
7
|
## DOM
|
|
8
8
|
<div class="kpt-chat-host">
|
|
9
|
-
<p class="kpt-chat__offline" role="status"
|
|
9
|
+
<p class="kpt-chat__offline" role="status">...</p>
|
|
10
10
|
<div class="kpt-chat__body">
|
|
11
11
|
<div class="kpt-chat__viewport" role="log" aria-live="polite">
|
|
12
12
|
<p class="kpt-chat__date" role="separator">Today</p>
|
|
13
|
-
<div class="kpt-chat-message-host"
|
|
14
|
-
<p class="kpt-chat__unread" role="separator"
|
|
15
|
-
<div class="kpt-chat-typing-host"
|
|
13
|
+
<div class="kpt-chat-message-host">...</div>
|
|
14
|
+
<p class="kpt-chat__unread" role="separator">...</p>
|
|
15
|
+
<div class="kpt-chat-typing-host">...</div>
|
|
16
16
|
</div>
|
|
17
17
|
<p class="kpt-chat__day" aria-hidden="true">Today</p>
|
|
18
18
|
<button class="kpt-chat__jump">3 new messages</button>
|
|
@@ -20,31 +20,32 @@ Import: `import { KptChat } from '@konce-pt/react/chat';`
|
|
|
20
20
|
</div>
|
|
21
21
|
|
|
22
22
|
## Props
|
|
23
|
-
- `messages`: `KptChatMessage<T>[]`
|
|
24
|
-
- `currentUser`: string
|
|
23
|
+
- `messages`: `KptChatMessage<T>[]` - **in chronological order**; the component does not sort
|
|
24
|
+
- `currentUser`: string - the author id treated as "me"
|
|
25
25
|
- `groupGapMs`: number (default `KPT_CHAT_GROUP_GAP_MS`, 5 min)
|
|
26
|
-
- `unreadFrom`: string | null
|
|
26
|
+
- `unreadFrom`: string | null - the id of the first unread message
|
|
27
27
|
- `offline`: boolean, `typing`: `KptChatAuthor[]`, `autoScroll`: boolean (default true)
|
|
28
|
-
- `actions`: boolean
|
|
29
|
-
- `reactionOptions`: `readonly KptChatReactionOption[]` (default `KPT_CHAT_REACTIONS`)
|
|
30
|
-
- `
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- `
|
|
28
|
+
- `actions`: boolean - reply and react buttons on hover; `emptyLabel`: string
|
|
29
|
+
- `reactionOptions`: `readonly KptChatReactionOption[]` (default `KPT_CHAT_REACTIONS`) - passed to the bubbles
|
|
30
|
+
- `enterMotion`: `'spring' | 'fade' | 'none'` (default from `KptMotionProvider`, else `spring`) - see "Motion"
|
|
31
|
+
- `onRetry` / `onReply` - `(message) => void`; `onReact` - `(event: KptChatReactEvent) => void`
|
|
32
|
+
(`{ message, emoji }`); `onQuoted` - `(quote) => void`
|
|
33
|
+
- `onLoadMore` - fired once when the viewport reaches the top, not on every scroll event
|
|
34
|
+
- `renderMessage(message, row)` - the equivalent of `<ng-template let-message>`; it replaces the
|
|
34
35
|
bubble's text, and the bubble, its grouping and its meta row stay in place
|
|
35
36
|
- `className`, `ref` and every other `<div>` prop go to the host
|
|
36
37
|
|
|
37
38
|
## The composer is a sibling, not a slot
|
|
38
39
|
A read-only conversation (an archive, a preview) should not have to carry a text field it never
|
|
39
40
|
shows, so `KptChatComposer` is placed next to the list rather than inside it. The parent is what
|
|
40
|
-
gives the list its height
|
|
41
|
+
gives the list its height - `.kpt-chat-host` is a column flexbox with `min-height: 0`.
|
|
41
42
|
|
|
42
43
|
## Transport stays in the application
|
|
43
44
|
The component takes messages and only reports. Retrying a send is a status change the application
|
|
44
45
|
makes; `mergeStatus()` from `@konce-pt/chat` is there for out-of-order acks.
|
|
45
46
|
|
|
46
47
|
## Bubble actions: reply and react
|
|
47
|
-
`actions` puts two buttons beside the bubble. The arrow emits `onReply` with the message
|
|
48
|
+
`actions` puts two buttons beside the bubble. The arrow emits `onReply` with the message -
|
|
48
49
|
`replyRefFrom()` from `@konce-pt/chat` turns it into the `replyTo` the composer's quote bar wants.
|
|
49
50
|
The smiley opens a picker of five reactions (`KPT_CHAT_REACTIONS`) and emits `onReact` with the
|
|
50
51
|
chosen emoji; `toggleReaction(message.reactions, emoji)` is the arithmetic that puts it in the
|
|
@@ -57,6 +58,20 @@ re-render and resize) the component measures the separators, the unread divider
|
|
|
57
58
|
notices, hands the rectangles to `chatDayIndicator()` from `@konce-pt/chat` and swaps the pill's
|
|
58
59
|
text; a centred label driving into the pill's band puts the pill out, never the content.
|
|
59
60
|
|
|
61
|
+
## Motion
|
|
62
|
+
`enterMotion` (`spring | fade | none`) on the chat, the bubble and the dock:
|
|
63
|
+
- a new message at the bottom - your own grows from the composer side, someone else's comes in from
|
|
64
|
+
the sender's side, sharpening out of a blur; the first load and older messages loaded at the top
|
|
65
|
+
(`loadMore`) do not move - they are not news;
|
|
66
|
+
- a new reaction pops in, a changed count rolls in like a drum, a new status icon turns into place
|
|
67
|
+
(only after the bubble's first render, so loaded history stays still);
|
|
68
|
+
- the dock: `spring` grows the window out of the button (a capsule the size of the FAB opens into
|
|
69
|
+
the panel), `fade` slides and fades it as before.
|
|
70
|
+
|
|
71
|
+
With no value it takes `enter` from `KptMotionProvider` (default `spring`); `enabled: false` and the system
|
|
72
|
+
"reduce motion" setting always win. The typing dots are a state indicator - with motion off they
|
|
73
|
+
pulse slower instead of stopping.
|
|
74
|
+
|
|
60
75
|
## Examples
|
|
61
76
|
<KptChat messages={messages} currentUser="me" typing={typing} onRetry={resend} />
|
|
62
77
|
<KptChat messages={messages} currentUser="me" offline unreadFrom="m-42" onLoadMore={loadOlder} />
|
|
@@ -76,3 +91,12 @@ pill `--kpt-color-primary-border` + `--kpt-elevation-2`.
|
|
|
76
91
|
`role="log"` with `aria-live="polite"` announces a new message without cutting off what is being
|
|
77
92
|
read. Separators are `role="separator"` with a label. Auto-scroll uses `behavior: 'auto'` under
|
|
78
93
|
`prefers-reduced-motion`.
|
|
94
|
+
|
|
95
|
+
## Keyboard, counters and history
|
|
96
|
+
The scrolling history (`role="log"`) is a Tab stop named "Conversation history" (`chat.history`), so the
|
|
97
|
+
keyboard can scroll it even when no bubble holds a focusable element. The "new messages" button counts
|
|
98
|
+
the messages that actually arrived (a batch of five gives "5"). The typing indicator sits inside the log
|
|
99
|
+
but with `aria-live="off"`, so "X is typing..." is not announced like a message. Older messages loaded at
|
|
100
|
+
the top keep the view on the same message, also in Safari (no `overflow-anchor`). The composer reports
|
|
101
|
+
typing on the first keystroke and then at most every 3 s (`KPT_CHAT_TYPING_THROTTLE_MS`). A custom
|
|
102
|
+
reaction option may carry `label` - its accessible name.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type ComponentPropsWithRef } from 'react';
|
|
2
|
-
import type
|
|
2
|
+
import { type KptChatReplyRef } from '@konce-pt/chat';
|
|
3
3
|
import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
4
|
-
|
|
4
|
+
import { type KptSpeechColor } from '../speech/speech-button.tsx';
|
|
5
|
+
/** Ładunek wysyłki. Kompozytor niczego nie wysyła - pakuje dane i oddaje aplikacji. */
|
|
5
6
|
export interface KptChatComposerSubmit {
|
|
6
7
|
text: string;
|
|
7
8
|
files: readonly File[];
|
|
@@ -14,28 +15,40 @@ export interface KptChatComposerProps extends Omit<ComponentPropsWithRef<'div'>,
|
|
|
14
15
|
/** Podpowiedź w pustym polu; bez niej etykieta ze słownika. */
|
|
15
16
|
placeholder?: string;
|
|
16
17
|
disabled?: boolean;
|
|
17
|
-
/** Brak połączenia
|
|
18
|
+
/** Brak połączenia - przycisk mówi o kolejkowaniu, nie o wysyłce. */
|
|
18
19
|
offline?: boolean;
|
|
19
20
|
allowAttachments?: boolean;
|
|
20
21
|
/** Ile wierszy pole może urosnąć, zanim zacznie się przewijać. */
|
|
21
22
|
maxRows?: number;
|
|
22
23
|
enterToSend?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Mikrofon do dyktowania (Web Speech API) między polem a przyciskiem wysyłki. Bez wsparcia
|
|
26
|
+
* przeglądarki się nie pokazuje. Wysyłka w trakcie dyktowania zatwierdza to, co widać w polu.
|
|
27
|
+
*/
|
|
28
|
+
speech?: boolean;
|
|
29
|
+
/** Język dyktowania (BCP 47); bez niego z `KptI18nProvider`. */
|
|
30
|
+
speechLang?: string;
|
|
31
|
+
/** Kolor "stop" i fali w trakcie nasłuchu; domyślnie kolor motywu. */
|
|
32
|
+
speechColor?: KptSpeechColor;
|
|
23
33
|
/** Wiadomość, na którą odpowiadamy. Po wysłaniu czyści się razem z treścią. */
|
|
24
34
|
replyTo?: KptChatReplyRef | null;
|
|
25
35
|
defaultReplyTo?: KptChatReplyRef | null;
|
|
26
36
|
onReplyToChange?: (replyTo: KptChatReplyRef | null) => void;
|
|
27
37
|
onSend?: (payload: KptChatComposerSubmit) => void;
|
|
28
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Sygnał "piszę" dla drugiej strony: przy pierwszym znaku, a w trakcie pisania najwyżej raz na
|
|
40
|
+
* `KPT_CHAT_TYPING_THROTTLE_MS` (3 s) - nie przy każdym znaku.
|
|
41
|
+
*/
|
|
29
42
|
onTyping?: () => void;
|
|
30
43
|
}
|
|
31
44
|
/**
|
|
32
|
-
* Pole pisania wiadomości
|
|
45
|
+
* Pole pisania wiadomości - autorosnące, z załącznikami i paskiem cytatu.
|
|
33
46
|
*
|
|
34
47
|
* `Enter` wysyła, `Shift+Enter` łamie linię (`enterToSend={false}` odwraca układ).
|
|
35
|
-
* Przy `offline` przycisk zmienia etykietę na kolejkowanie
|
|
48
|
+
* Przy `offline` przycisk zmienia etykietę na kolejkowanie - wiadomość dalej da się napisać
|
|
36
49
|
* i oddać aplikacji, bo to ona decyduje, co zrobić z kolejką.
|
|
37
50
|
*
|
|
38
51
|
* @example
|
|
39
52
|
* <KptChatComposer allowAttachments onSend={(payload) => send(payload)} />
|
|
40
53
|
*/
|
|
41
|
-
export declare function KptChatComposer({ value, defaultValue, onValueChange, placeholder, disabled, offline, allowAttachments, maxRows, enterToSend, replyTo, defaultReplyTo, onReplyToChange, onSend, onTyping, locale, dictionary, className, ...rest }: Readonly<KptChatComposerProps>): import("react").JSX.Element;
|
|
54
|
+
export declare function KptChatComposer({ value, defaultValue, onValueChange, placeholder, disabled, offline, allowAttachments, maxRows, enterToSend, speech, speechLang, speechColor, replyTo, defaultReplyTo, onReplyToChange, onSend, onTyping, locale, dictionary, className, ...rest }: Readonly<KptChatComposerProps>): import("react").JSX.Element;
|