@inkra/react 0.4.3 → 0.6.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 +109 -0
- package/dist/audio-player/index.js +6 -4
- package/dist/breadcrumb/index.d.ts +16 -4
- package/dist/breadcrumb/index.js +24 -8
- package/dist/calendar/index.js +10 -4
- package/dist/calendar/locales.d.ts +7 -0
- package/dist/calendar/locales.js +2 -0
- package/dist/carousel/index.js +8 -5
- package/dist/choice-grid/index.js +3 -1
- package/dist/color-picker/GradientEditor.d.ts +2 -1
- package/dist/color-picker/GradientEditor.js +10 -9
- package/dist/color-picker/index.js +12 -10
- package/dist/content/index.js +4 -1
- package/dist/data-table/index.d.ts +1 -1
- package/dist/data-table/index.js +4 -1
- package/dist/date-picker/index.js +11 -13
- package/dist/day-agenda/index.d.ts +1 -1
- package/dist/day-agenda/index.js +4 -1
- package/dist/dockable-panel/index.js +10 -8
- package/dist/drawer/index.js +7 -2
- package/dist/editable/index.js +8 -5
- package/dist/form/Input.js +4 -1
- package/dist/form/Textarea.js +4 -2
- package/dist/heatmap/index.js +4 -1
- package/dist/hotkey/index.js +4 -1
- package/dist/i18n/catalog.d.ts +5 -0
- package/dist/i18n/catalog.js +289 -0
- package/dist/i18n/index.d.ts +23 -0
- package/dist/i18n/index.js +50 -0
- package/dist/image-cropper/index.js +17 -15
- package/dist/image-viewer/VideoResource.js +14 -12
- package/dist/image-viewer/index.js +23 -21
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/input-number/index.js +4 -1
- package/dist/internal/textRenderer.d.ts +1 -0
- package/dist/internal/textRenderer.js +10 -2
- package/dist/journey-map/index.d.ts +1 -1
- package/dist/journey-map/index.js +6 -3
- package/dist/keypad/index.js +4 -1
- package/dist/log/index.js +13 -11
- package/dist/markdown/index.js +11 -9
- package/dist/node-graph/index.d.ts +1 -1
- package/dist/node-graph/index.js +14 -3
- package/dist/number-ticker/index.js +4 -1
- package/dist/overflow-list/index.js +4 -4
- package/dist/overlay/Overlay.js +7 -2
- package/dist/pagination/index.js +7 -5
- package/dist/pan-zoom/index.js +6 -3
- package/dist/radar/index.js +4 -1
- package/dist/range-slider/index.js +4 -3
- package/dist/rating/index.js +5 -2
- package/dist/resizable/index.d.ts +1 -1
- package/dist/resizable/index.js +4 -1
- package/dist/select/SearchableSelect.js +3 -1
- package/dist/select/Select.js +3 -1
- package/dist/select/StepperSelect.js +5 -2
- package/dist/sortable/index.js +11 -9
- package/dist/sparkline/index.js +7 -7
- package/dist/steps/index.js +4 -1
- package/dist/styles/breadcrumb.css +96 -5
- package/dist/styles/select.css +8 -6
- package/dist/styles.css +104 -11
- package/dist/tabs/index.js +4 -1
- package/dist/tag-input/index.js +12 -17
- package/dist/theme/index.d.ts +11 -0
- package/dist/theme/index.js +23 -0
- package/dist/time-picker/index.js +7 -7
- package/dist/timeline/index.js +4 -1
- package/dist/toast/index.d.ts +1 -1
- package/dist/toast/index.js +4 -1
- package/dist/transfer/index.js +30 -27
- package/dist/tree/index.js +7 -2
- package/dist/tree-select/index.js +3 -1
- package/dist/upload/index.js +21 -18
- package/dist/virtual-list/index.js +4 -1
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -48,6 +48,104 @@ export function Actions() {
|
|
|
48
48
|
|
|
49
49
|
To use only the design tokens, import `@inkra/react/tokens.css` instead.
|
|
50
50
|
|
|
51
|
+
## Theme Provider
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import '@inkra/react/styles.css';
|
|
55
|
+
import { ThemeProvider } from '@inkra/react/theme';
|
|
56
|
+
import type { InkraThemeTokens } from '@inkra/react/theme';
|
|
57
|
+
|
|
58
|
+
const tokens = {
|
|
59
|
+
'--inkra-accent': '#4b96aa',
|
|
60
|
+
'--inkra-icon-stroke-width': '1.5px',
|
|
61
|
+
} satisfies InkraThemeTokens;
|
|
62
|
+
|
|
63
|
+
<ThemeProvider theme="auto" tokens={tokens}>
|
|
64
|
+
<App />
|
|
65
|
+
</ThemeProvider>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`ThemeProvider` is also exported from the package root. It renders a local `div`
|
|
69
|
+
scope, accepts its normal HTML attributes and forwards its ref. It never changes
|
|
70
|
+
the document theme or stores a preference. `theme` supports `light`, `dark`, and
|
|
71
|
+
`auto`; omit it to inherit the surrounding CSS theme. Auto uses native CSS media
|
|
72
|
+
queries and works with SSR without resolving the system preference in JavaScript.
|
|
73
|
+
|
|
74
|
+
`tokens` accepts partial `--inkra-*` variables for color, fonts, geometry and
|
|
75
|
+
pencil rendering. Supply units for lengths (`"1.5px"`); unitless numbers work for
|
|
76
|
+
intensity and similar values. An inner scope without `theme` inherits outer
|
|
77
|
+
tokens; an explicit mode establishes that mode's built-in variables before local
|
|
78
|
+
overrides. `style` takes precedence over `tokens`. User token overrides are
|
|
79
|
+
suspended while forced colors are active so the system palette can take over.
|
|
80
|
+
|
|
81
|
+
Custom colors do not automatically adapt to light/dark modes. Supply appropriate
|
|
82
|
+
variables for each mode, or use CSS media queries. Existing component portals
|
|
83
|
+
inherit the trigger scope and track its live changes. The scope has no default
|
|
84
|
+
background or spacing; use a surface or your own layout when needed. It composes
|
|
85
|
+
with `InkraProvider` for language configuration without changing input state.
|
|
86
|
+
|
|
87
|
+
## Internationalization
|
|
88
|
+
|
|
89
|
+
Wrap your application in `InkraProvider` to localize component-owned copy and
|
|
90
|
+
accessible labels. Built-in dictionaries are `en`, `zh-CN`, `ja`, `ko`, and `fr`.
|
|
91
|
+
All five share the same typed keys. Regional tags such as `en-GB`, `ja-JP`,
|
|
92
|
+
`ko-KR`, `fr-CA` and `zh-Hans-CN` select the matching language while keeping
|
|
93
|
+
regional date/number formatting. No provider preserves the English defaults.
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import { InkraProvider, Input, Pagination } from '@inkra/react';
|
|
97
|
+
import type { InkraDictionary } from '@inkra/react/i18n';
|
|
98
|
+
|
|
99
|
+
const messages = {
|
|
100
|
+
'input.clear': 'Clear note',
|
|
101
|
+
'pagination.page': 'Open page {page}',
|
|
102
|
+
} satisfies InkraDictionary;
|
|
103
|
+
|
|
104
|
+
<InkraProvider locale="fr-CA" messages={messages}>
|
|
105
|
+
<Input clearable defaultValue="My note" aria-label="Note" />
|
|
106
|
+
<Pagination totalPages={5} />
|
|
107
|
+
</InkraProvider>;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`messages` is a partial dictionary; developers can import JSON or adapt their
|
|
111
|
+
existing i18n resource into these flat keys. Inspect `inkraLocales.en` for the
|
|
112
|
+
complete key list and source templates, or copy another built-in dictionary.
|
|
113
|
+
The provider, dictionaries, types, `useInkraLocale` and
|
|
114
|
+
`createInkraTranslator` are also exported from `@inkra/react/i18n`.
|
|
115
|
+
|
|
116
|
+
- Precedence: explicit component labels/props, inner provider overrides, inherited
|
|
117
|
+
overrides, then the built-in dictionary. Unknown languages use English copy
|
|
118
|
+
while valid `Intl` locale formatting is preserved. Invalid locale strings use `en-US`.
|
|
119
|
+
- Nested providers merge by key, even when the inner locale changes. Pass the
|
|
120
|
+
desired override dictionary on language changes; inherited overrides are intentional.
|
|
121
|
+
- `undefined` entries do not override; empty strings do. Avoid empty accessible
|
|
122
|
+
labels on interactive controls. Use `satisfies InkraDictionary` to catch key typos.
|
|
123
|
+
- Preserve template placeholders such as `{page}`, `{count}` and `{label}`.
|
|
124
|
+
Interpolation is a single literal-text pass, not HTML, ICU, or executable code.
|
|
125
|
+
Missing placeholder values are left visible rather than silently removed.
|
|
126
|
+
- Explicit component `locale` props take priority over the provider. Calendar
|
|
127
|
+
also retains its DayPicker locale/labels/formatters API. NumberTicker's
|
|
128
|
+
explicit compact-unit policies remain independent of regional number formatting.
|
|
129
|
+
- Language and dictionary updates do not remount children or clear form drafts.
|
|
130
|
+
The provider adds no HTML wrapper and does not mutate the document language.
|
|
131
|
+
Set `lang` on your page or locale-scoped container; set `dir` separately if needed.
|
|
132
|
+
- Application labels, option content, errors supplied by your application, and
|
|
133
|
+
stored/submitted values are not automatically translated. InkraProvider also
|
|
134
|
+
passes its locale to React Aria's internal announcements; third-party/native
|
|
135
|
+
messages are not keys in the Inkra dictionary.
|
|
136
|
+
- Use identical locale/dictionary data for SSR and hydration. Messages may change
|
|
137
|
+
after hydration; the provider does not read browser language or local storage.
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
import { InkraProvider, inkraLocales } from '@inkra/react/i18n';
|
|
141
|
+
|
|
142
|
+
const customLanguage = { ...inkraLocales.en, 'input.clear': 'Effacer la note' };
|
|
143
|
+
|
|
144
|
+
<InkraProvider locale="fr" messages={customLanguage}>
|
|
145
|
+
{children}
|
|
146
|
+
</InkraProvider>;
|
|
147
|
+
```
|
|
148
|
+
|
|
51
149
|
## Button
|
|
52
150
|
|
|
53
151
|
`Button` forwards its ref and native button attributes. Its default `type` is `button`, so placing it inside a form will not submit unexpectedly.
|
|
@@ -189,6 +287,17 @@ Canvas failures, forced colors and printing retain an SVG progress fallback.
|
|
|
189
287
|
|
|
190
288
|
## Menus And Content
|
|
191
289
|
|
|
290
|
+
`Breadcrumb` exposes `Root`, `List`, `Item`, `Link`, `MenuTrigger`,
|
|
291
|
+
`ContextLink`, `Page` and `Separator`. `Link` renders a real anchor and defaults
|
|
292
|
+
to the pencil-underlined `link` appearance; `startIcon` and `endIcon` occupy the
|
|
293
|
+
logical sides and follow RTL. `Page` accepts the same icon slots. Page, link and
|
|
294
|
+
menu-trigger content share a 44px default hit height, 15px text, 20px icon slot,
|
|
295
|
+
8px gap and 12px logical padding so a header can change item semantics without
|
|
296
|
+
moving its baseline. Disabled links remove `href` and leave the tab order. Use
|
|
297
|
+
`MenuTrigger` inside `DropdownMenu.Root` for an item that selects another path,
|
|
298
|
+
and `ContextLink` inside `ContextMenu.Root` for pointer, keyboard and optional
|
|
299
|
+
long-press actions without adding a second focus target.
|
|
300
|
+
|
|
192
301
|
`DropdownMenu` exposes `Root`, `Trigger`, `Portal`, `Content`, `Item`, `CheckboxItem`, `RadioGroup`, `RadioItem`, `Group`, `Label` and `Separator`. It supports controlled open state, placement/collision props, disabled items, keyboard navigation and focus return. Use `Trigger asChild` with a Button; use `Item.destructive` for dangerous actions. Portal content inherits the trigger theme. Submenus are not included yet.
|
|
193
302
|
|
|
194
303
|
`Alert.Root` accepts `variant="info | success | warning | danger"`, an optional decorative `icon`, and native attributes. Compose with `Alert.Title` and `Alert.Description`. The default `role="status"` is polite; explicitly use `role="alert"` only for urgent feedback.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useRef, useState } from 'react';
|
|
3
4
|
import { Button } from '../Button.js';
|
|
4
5
|
import { PencilIcon } from '../PencilIcon.js';
|
|
@@ -21,14 +22,15 @@ const mutePaths = [
|
|
|
21
22
|
{ d: 'm16.5 14.5 5-5' },
|
|
22
23
|
{ d: 'm16.5 9.5 5 5' },
|
|
23
24
|
];
|
|
24
|
-
const DEFAULT_LABELS = {
|
|
25
|
-
controls: '
|
|
26
|
-
};
|
|
25
|
+
const DEFAULT_LABELS = (t) => ({
|
|
26
|
+
controls: t('audio.controls'), audio: t('audio.label'), play: t('audio.play'), pause: t('audio.pause'), mute: t('audio.mute'), unmute: t('audio.unmute'), seek: t('audio.seek'), volume: t('audio.volume'), rate: t('audio.rate'), loading: t('audio.loading'), blocked: t('audio.blocked'), error: t('audio.error'),
|
|
27
|
+
});
|
|
27
28
|
const rates = [0.75, 1, 1.25, 1.5, 2];
|
|
28
29
|
function clamp(value, min, max) { return Number.isFinite(value) ? Math.min(max, Math.max(min, value)) : min; }
|
|
29
30
|
function formatTime(value) { if (!Number.isFinite(value) || value < 0)
|
|
30
31
|
return '0:00'; const seconds = Math.floor(value); return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, '0')}`; }
|
|
31
32
|
export const AudioPlayer = forwardRef(function AudioPlayer({ src, preload = 'metadata', autoPlay = false, crossOrigin, className, defaultMuted = false, defaultPlaybackRate = 1, defaultVolume = 1, volume, muted, playbackRate, onVolumeChange, onMutedChange, onPlaybackRateChange, onTimeChange, onStateChange, onError, labels, renderControls, audioProps, ...props }, forwardedRef) {
|
|
33
|
+
const { t } = useInkraLocale();
|
|
32
34
|
const id = useId();
|
|
33
35
|
const audioRef = useRef(null);
|
|
34
36
|
const rootRef = useRef(null);
|
|
@@ -42,7 +44,7 @@ export const AudioPlayer = forwardRef(function AudioPlayer({ src, preload = 'met
|
|
|
42
44
|
controlledRef.current = { volume, muted, playbackRate };
|
|
43
45
|
const callbacksRef = useRef({ onVolumeChange, onMutedChange, onPlaybackRateChange, onTimeChange, onStateChange, onError });
|
|
44
46
|
callbacksRef.current = { onVolumeChange, onMutedChange, onPlaybackRateChange, onTimeChange, onStateChange, onError };
|
|
45
|
-
const mergedLabels = { ...DEFAULT_LABELS, ...labels };
|
|
47
|
+
const mergedLabels = { ...DEFAULT_LABELS(t), ...labels };
|
|
46
48
|
const update = useCallback((patch) => {
|
|
47
49
|
const current = stateRef.current;
|
|
48
50
|
const changed = Object.keys(patch).some(key => !Object.is(current[key], patch[key]));
|
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
import { type ComponentPropsWithoutRef } from 'react';
|
|
2
|
-
import { type ButtonLinkProps } from '../Button.js';
|
|
1
|
+
import { type ComponentPropsWithoutRef, type ReactNode } from 'react';
|
|
2
|
+
import { type ButtonLinkProps, type ButtonProps } from '../Button.js';
|
|
3
|
+
import { type ContextMenuTriggerProps } from '../context-menu/index.js';
|
|
3
4
|
export type BreadcrumbProps = ComponentPropsWithoutRef<'nav'>;
|
|
4
5
|
export type BreadcrumbListProps = ComponentPropsWithoutRef<'ol'>;
|
|
5
6
|
export type BreadcrumbItemProps = ComponentPropsWithoutRef<'li'>;
|
|
6
7
|
export type BreadcrumbLinkProps = ButtonLinkProps;
|
|
7
|
-
export type
|
|
8
|
+
export type BreadcrumbMenuTriggerProps = ButtonProps;
|
|
9
|
+
export interface BreadcrumbContextLinkProps extends BreadcrumbLinkProps {
|
|
10
|
+
exclude?: ContextMenuTriggerProps['exclude'];
|
|
11
|
+
longPress?: ContextMenuTriggerProps['longPress'];
|
|
12
|
+
nativeContextMenu?: ContextMenuTriggerProps['nativeContextMenu'];
|
|
13
|
+
}
|
|
14
|
+
export interface BreadcrumbPageProps extends ComponentPropsWithoutRef<'span'> {
|
|
15
|
+
endIcon?: ReactNode;
|
|
16
|
+
startIcon?: ReactNode;
|
|
17
|
+
}
|
|
8
18
|
export type BreadcrumbSeparatorProps = ComponentPropsWithoutRef<'li'>;
|
|
9
19
|
export declare const Breadcrumb: {
|
|
10
20
|
Root: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & import("react").RefAttributes<HTMLElement>>;
|
|
11
21
|
List: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").OlHTMLAttributes<HTMLOListElement>, HTMLOListElement>, "ref"> & import("react").RefAttributes<HTMLOListElement>>;
|
|
12
22
|
Item: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "ref"> & import("react").RefAttributes<HTMLLIElement>>;
|
|
13
23
|
Link: import("react").ForwardRefExoticComponent<ButtonLinkProps & import("react").RefAttributes<HTMLAnchorElement>>;
|
|
14
|
-
|
|
24
|
+
MenuTrigger: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
25
|
+
ContextLink: import("react").ForwardRefExoticComponent<BreadcrumbContextLinkProps & import("react").RefAttributes<HTMLAnchorElement>>;
|
|
26
|
+
Page: import("react").ForwardRefExoticComponent<BreadcrumbPageProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
15
27
|
Separator: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "ref"> & import("react").RefAttributes<HTMLLIElement>>;
|
|
16
28
|
};
|
package/dist/breadcrumb/index.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
3
|
+
import { forwardRef, } from 'react';
|
|
4
|
+
import { Button, ButtonLink, } from '../Button.js';
|
|
5
|
+
import { ContextMenu, } from '../context-menu/index.js';
|
|
6
|
+
import { DropdownMenu } from '../dropdown-menu/index.js';
|
|
4
7
|
import { PencilText } from '../PencilText.js';
|
|
5
8
|
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
6
9
|
const copy = (children) => typeof children === 'string' ? _jsx(PencilText, { children: children }) : children;
|
|
7
|
-
const Root = forwardRef(function BreadcrumbRoot(
|
|
10
|
+
const Root = forwardRef(function BreadcrumbRoot(inkraProps, ref) {
|
|
11
|
+
const { t } = useInkraLocale();
|
|
12
|
+
const { className, 'aria-label': label = t('breadcrumb.label'), ...props } = inkraProps;
|
|
8
13
|
return _jsx("nav", { ...props, ref: ref, "aria-label": label, className: classes('inkra-breadcrumb', className) });
|
|
9
14
|
});
|
|
10
15
|
const List = forwardRef(function BreadcrumbList({ className, ...props }, ref) {
|
|
@@ -13,13 +18,24 @@ const List = forwardRef(function BreadcrumbList({ className, ...props }, ref) {
|
|
|
13
18
|
const Item = forwardRef(function BreadcrumbItem({ className, ...props }, ref) {
|
|
14
19
|
return _jsx("li", { ...props, ref: ref, className: classes('inkra-breadcrumb__item', className) });
|
|
15
20
|
});
|
|
16
|
-
const Link = forwardRef(function BreadcrumbLink({ className, variant = '
|
|
21
|
+
const Link = forwardRef(function BreadcrumbLink({ className, variant = 'link', ...props }, ref) {
|
|
17
22
|
return _jsx(ButtonLink, { ...props, ref: ref, variant: variant, className: classes('inkra-breadcrumb__link', className) });
|
|
18
23
|
});
|
|
19
|
-
const
|
|
20
|
-
return _jsx(
|
|
24
|
+
const MenuTrigger = forwardRef(function BreadcrumbMenuTrigger({ className, disabled = false, loading = false, variant = 'link', ...props }, ref) {
|
|
25
|
+
return _jsx(DropdownMenu.Trigger, { asChild: true, disabled: disabled || loading, children: _jsx(Button, { ...props, ref: ref, disabled: disabled, loading: loading, variant: variant, className: classes('inkra-breadcrumb__trigger', className) }) });
|
|
26
|
+
});
|
|
27
|
+
const ContextLinkAnchor = forwardRef(function BreadcrumbContextLinkAnchor({ 'aria-disabled': ariaDisabled, disabled = false, ...props }, ref) {
|
|
28
|
+
const contextDisabled = ariaDisabled === true || ariaDisabled === 'true';
|
|
29
|
+
return _jsx(Link, { ...props, ref: ref, "aria-disabled": contextDisabled || disabled || undefined, disabled: contextDisabled || disabled });
|
|
30
|
+
});
|
|
31
|
+
const ContextLink = forwardRef(function BreadcrumbContextLink({ className, disabled = false, exclude, longPress, nativeContextMenu, ...props }, ref) {
|
|
32
|
+
return _jsx(ContextMenu.Trigger, { ...props, as: ContextLinkAnchor, className: classes('inkra-breadcrumb__context-link', className), disabled: disabled || props.loading, exclude: exclude, longPress: longPress, nativeContextMenu: nativeContextMenu, ref: ref });
|
|
33
|
+
});
|
|
34
|
+
const Page = forwardRef(function BreadcrumbPage({ className, children, endIcon, startIcon, ...props }, ref) {
|
|
35
|
+
const icon = (side, value) => value == null ? null : _jsx("span", { "aria-hidden": "true", className: `inkra-breadcrumb__icon inkra-breadcrumb__icon--${side}`, children: value });
|
|
36
|
+
return _jsxs("span", { ...props, ref: ref, "aria-current": "page", className: classes('inkra-breadcrumb__page', className), children: [icon('start', startIcon), _jsx("span", { className: "inkra-breadcrumb__label", children: copy(children) }), icon('end', endIcon)] });
|
|
21
37
|
});
|
|
22
38
|
const Separator = forwardRef(function BreadcrumbSeparator({ className, children = '/', ...props }, ref) {
|
|
23
39
|
return _jsx("li", { ...props, ref: ref, role: "presentation", "aria-hidden": "true", className: classes('inkra-breadcrumb__separator', className), children: copy(children) });
|
|
24
40
|
});
|
|
25
|
-
export const Breadcrumb = { Root, List, Item, Link, Page, Separator };
|
|
41
|
+
export const Breadcrumb = { Root, List, Item, Link, MenuTrigger, ContextLink, Page, Separator };
|
package/dist/calendar/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale, resolveInkraLocale } from '../i18n/index.js';
|
|
3
|
+
import { calendarLocales } from './locales.js';
|
|
2
4
|
import { createContext, useContext, useMemo, useState } from 'react';
|
|
3
5
|
import { CaptionLabel, Day, DayButton, DayPicker, Weekday } from 'react-day-picker';
|
|
4
6
|
import { Button } from '../Button.js';
|
|
@@ -25,6 +27,7 @@ function CalendarChevron({ className, orientation = 'left', size = 28 }) {
|
|
|
25
27
|
}
|
|
26
28
|
// The trip calendar uses a full-cell date target with sibling event buttons.
|
|
27
29
|
function CalendarCell({ children, day, modifiers, ...props }) {
|
|
30
|
+
const { t } = useInkraLocale();
|
|
28
31
|
const { eventsByDay, appearance, onEventSelect, renderDayAccessory, maxEventsPerDay, showDayEventsLabel } = useContext(EventContext);
|
|
29
32
|
const [expandedDay, setExpandedDay] = useState();
|
|
30
33
|
if (appearance === 'picker')
|
|
@@ -33,15 +36,18 @@ function CalendarCell({ children, day, modifiers, ...props }) {
|
|
|
33
36
|
const limit = maxEventsPerDay !== undefined && Number.isFinite(maxEventsPerDay) ? Math.max(0, Math.floor(maxEventsPerDay)) : entries.length;
|
|
34
37
|
const expanded = expandedDay === dayKey(day.date);
|
|
35
38
|
const shown = expanded || limit >= entries.length ? entries : entries.slice(0, limit);
|
|
36
|
-
return _jsx(Day, { ...props, day: day, modifiers: modifiers, children: _jsxs("div", { className: "inkra-calendar__day-card", children: [_jsx(PencilSurface, { variant: modifiers.selected ? 'action' : 'quiet', radius: 8, className: "inkra-calendar__day-paper", "aria-hidden": "true", seed: `day-${day.date.toISOString()}` }), children, renderDayAccessory && _jsx("div", { className: "inkra-calendar__accessory", children: renderDayAccessory(day.date) }), _jsxs("div", { className: "inkra-calendar__events", children: [shown.map((event, index) => _jsx(PencilSurface, { as: "button", variant: "quiet", radius: 3, className: "inkra-calendar__event-card", disabled: modifiers.disabled || !onEventSelect, style: event.color ? { '--inkra-accent-soft': event.color } : undefined, "aria-label": `${event.label}${event.description ? `, ${event.description}` : ''}`, title: event.description ?? event.label, onClick: click => { click.stopPropagation(); onEventSelect?.(event); }, children: _jsx(PencilText, { ellipsis: true, children: event.label }) }, event.id ?? index)), entries.length > limit && _jsx(Button, { className: "inkra-calendar__events-toggle", size: "sm", variant: "ghost", "aria-expanded": expanded, onClick: click => { click.stopPropagation(); setExpandedDay(expanded ? undefined : dayKey(day.date)); }, children: showDayEventsLabel?.(day.date, entries.length, expanded) ?? (expanded ? '
|
|
39
|
+
return _jsx(Day, { ...props, day: day, modifiers: modifiers, children: _jsxs("div", { className: "inkra-calendar__day-card", children: [_jsx(PencilSurface, { variant: modifiers.selected ? 'action' : 'quiet', radius: 8, className: "inkra-calendar__day-paper", "aria-hidden": "true", seed: `day-${day.date.toISOString()}` }), children, renderDayAccessory && _jsx("div", { className: "inkra-calendar__accessory", children: renderDayAccessory(day.date) }), _jsxs("div", { className: "inkra-calendar__events", children: [shown.map((event, index) => _jsx(PencilSurface, { as: "button", variant: "quiet", radius: 3, className: "inkra-calendar__event-card", disabled: modifiers.disabled || !onEventSelect, style: event.color ? { '--inkra-accent-soft': event.color } : undefined, "aria-label": `${event.label}${event.description ? `, ${event.description}` : ''}`, title: event.description ?? event.label, onClick: click => { click.stopPropagation(); onEventSelect?.(event); }, children: _jsx(PencilText, { ellipsis: true, children: event.label }) }, event.id ?? index)), entries.length > limit && _jsx(Button, { className: "inkra-calendar__events-toggle", size: "sm", variant: "ghost", "aria-expanded": expanded, onClick: click => { click.stopPropagation(); setExpandedDay(expanded ? undefined : dayKey(day.date)); }, children: showDayEventsLabel?.(day.date, entries.length, expanded) ?? (expanded ? t('agenda.fewer') : t('agenda.all', { count: entries.length })) })] })] }) });
|
|
37
40
|
}
|
|
38
41
|
function CalendarDay({ children, modifiers, day, ...props }) {
|
|
42
|
+
const { t } = useInkraLocale();
|
|
39
43
|
const { eventsByDay, indicator, appearance, maxEventsPerDay, showDayEventsLabel } = useContext(EventContext);
|
|
40
44
|
const events = eventsByDay.get(dayKey(day.date)) ?? emptyEvents;
|
|
41
45
|
return _jsxs(DayButton, { ...props, day: day, modifiers: modifiers, "aria-label": [props['aria-label'], ...(maxEventsPerDay !== undefined && Number.isFinite(maxEventsPerDay) && events.length > Math.max(0, Math.floor(maxEventsPerDay))
|
|
42
|
-
? [showDayEventsLabel?.(day.date, events.length, false) ??
|
|
46
|
+
? [showDayEventsLabel?.(day.date, events.length, false) ?? t('agenda.count', { count: events.length })] : events.map(event => event.label))].filter(Boolean).join(', '), children: [modifiers.selected && appearance === 'picker' && _jsx(PencilSurface, { variant: "selection", className: "inkra-calendar__selection", "aria-hidden": "true" }), _jsx(PencilText, { children: String(children) }), appearance === 'picker' && events.length > 0 && indicator !== 'none' && _jsx("span", { className: "inkra-calendar__event", "data-indicator": indicator, "aria-hidden": "true", children: indicator === 'count' ? events.length : '\u2022' })] });
|
|
43
47
|
}
|
|
44
48
|
export function Calendar({ events = emptyEvents, eventIndicator = 'count', appearance = 'itinerary', onEventSelect, renderDayAccessory, displayRange, maxEventsPerDay, showDayEventsLabel, className, components, showOutsideDays = true, ...props }) {
|
|
49
|
+
const { locale, t } = useInkraLocale(props.locale?.code);
|
|
50
|
+
const eventSummary = useMemo(() => showDayEventsLabel ?? ((_date, total, expanded) => t(expanded ? 'agenda.fewer' : 'agenda.all', { count: total })), [showDayEventsLabel, t]);
|
|
45
51
|
const eventsByDay = useMemo(() => {
|
|
46
52
|
const index = new Map();
|
|
47
53
|
for (const event of events) {
|
|
@@ -54,7 +60,7 @@ export function Calendar({ events = emptyEvents, eventIndicator = 'count', appea
|
|
|
54
60
|
}
|
|
55
61
|
return index;
|
|
56
62
|
}, [events]);
|
|
57
|
-
const context = useMemo(() => ({ eventsByDay, indicator: eventIndicator, appearance, onEventSelect, renderDayAccessory, maxEventsPerDay, showDayEventsLabel }), [eventsByDay, eventIndicator, appearance, onEventSelect, renderDayAccessory, maxEventsPerDay,
|
|
63
|
+
const context = useMemo(() => ({ eventsByDay, indicator: eventIndicator, appearance, onEventSelect, renderDayAccessory, maxEventsPerDay, showDayEventsLabel: eventSummary }), [eventsByDay, eventIndicator, appearance, onEventSelect, renderDayAccessory, maxEventsPerDay, eventSummary]);
|
|
58
64
|
const hidden = displayRange ? [...(Array.isArray(props.hidden) ? props.hidden : props.hidden ? [props.hidden] : []), { before: displayRange.from }, { after: displayRange.to }] : props.hidden;
|
|
59
|
-
return _jsx(EventContext.Provider, { value: context, children: _jsx("div", { className: "inkra-calendar-scroll", "data-appearance": appearance, "data-event-summary": maxEventsPerDay !== undefined && Number.isFinite(maxEventsPerDay) || undefined, children: _jsx(DayPicker, { ...props, hidden: hidden, "data-appearance": appearance, "data-week-numbers": props.showWeekNumber || undefined, showOutsideDays: showOutsideDays, className: ['inkra-calendar', className].filter(Boolean).join(' '), components: { CaptionLabel: CalendarCaption, Weekday: CalendarWeekday, Chevron: CalendarChevron, PreviousMonthButton: CalendarMonthButton, NextMonthButton: CalendarMonthButton, Day: CalendarCell, DayButton: CalendarDay, ...components } }) }) });
|
|
65
|
+
return _jsx(EventContext.Provider, { value: context, children: _jsx("div", { className: "inkra-calendar-scroll", "data-appearance": appearance, "data-event-summary": maxEventsPerDay !== undefined && Number.isFinite(maxEventsPerDay) || undefined, children: _jsx(DayPicker, { ...props, locale: props.locale ?? calendarLocales[resolveInkraLocale(locale)], labels: { labelPrevious: () => t('datePicker.previous'), labelNext: () => t('datePicker.next'), ...props.labels }, hidden: hidden, "data-appearance": appearance, "data-week-numbers": props.showWeekNumber || undefined, showOutsideDays: showOutsideDays, className: ['inkra-calendar', className].filter(Boolean).join(' '), components: { CaptionLabel: CalendarCaption, Weekday: CalendarWeekday, Chevron: CalendarChevron, PreviousMonthButton: CalendarMonthButton, NextMonthButton: CalendarMonthButton, Day: CalendarCell, DayButton: CalendarDay, ...components } }) }) });
|
|
60
66
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const calendarLocales: {
|
|
2
|
+
en: import("react-day-picker/locale").DayPickerLocale;
|
|
3
|
+
'zh-CN': import("react-day-picker/locale").DayPickerLocale;
|
|
4
|
+
ja: import("react-day-picker/locale").DayPickerLocale;
|
|
5
|
+
ko: import("react-day-picker/locale").DayPickerLocale;
|
|
6
|
+
fr: import("react-day-picker/locale").DayPickerLocale;
|
|
7
|
+
};
|
package/dist/carousel/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import Autoplay from 'embla-carousel-autoplay';
|
|
3
4
|
import useEmblaCarousel from 'embla-carousel-react';
|
|
4
5
|
import { Children, forwardRef, useCallback, useEffect, useId, useImperativeHandle, useMemo, useRef, useState, } from 'react';
|
|
@@ -40,7 +41,9 @@ function useReducedMotion() {
|
|
|
40
41
|
}, []);
|
|
41
42
|
return reduced;
|
|
42
43
|
}
|
|
43
|
-
export const Carousel = forwardRef(function Carousel(
|
|
44
|
+
export const Carousel = forwardRef(function Carousel(inkraProps, forwardedRef) {
|
|
45
|
+
const { t } = useInkraLocale();
|
|
46
|
+
const { 'aria-label': ariaLabel = t('carousel.label'), align = 'start', autoplay = false, children, className, controls = true, currentIndex, defaultIndex = 0, dir, disabled = false, dragFree = false, emptyState, gap = 16, labels, loop = false, onBlurCapture, onCurrentIndexChange, onFocusCapture, onKeyDown, onPointerEnter, onPointerLeave, pagination = true, role = 'region', style, tabIndex, visibleItems = { base: 1, sm: 2, md: 3 }, ...props } = inkraProps;
|
|
44
47
|
const generatedId = useId();
|
|
45
48
|
const rootRef = useRef(null);
|
|
46
49
|
const slideItems = Children.toArray(children);
|
|
@@ -288,10 +291,10 @@ export const Carousel = forwardRef(function Carousel({ 'aria-label': ariaLabel =
|
|
|
288
291
|
'--inkra-carousel-visible-md': visible.md,
|
|
289
292
|
'--inkra-carousel-visible-lg': visible.lg,
|
|
290
293
|
};
|
|
291
|
-
const slideLabel = labels?.slide ?? ((index, total) =>
|
|
292
|
-
const pageLabel = labels?.page ?? ((index, total) =>
|
|
293
|
-
const statusLabel = labels?.status ?? ((index, total) =>
|
|
294
|
+
const slideLabel = labels?.slide ?? ((index, total) => t('carousel.slide', { index, total }));
|
|
295
|
+
const pageLabel = labels?.page ?? ((index, total) => t('carousel.page', { index, total }));
|
|
296
|
+
const statusLabel = labels?.status ?? ((index, total) => t('carousel.slide', { index, total }));
|
|
294
297
|
const showNavigation = controls && count > 1;
|
|
295
298
|
const showPagination = pagination && scrollSnaps.length > 1;
|
|
296
|
-
return _jsxs("div", { ...props, "aria-label": ariaLabel, "aria-roledescription": "carousel", className: ['inkra-carousel', className].filter(Boolean).join(' '), "data-autoplay": autoplayEnabled || undefined, "data-disabled": disabled || undefined, "data-playing": playing || undefined, dir: resolvedDir, onBlurCapture: handleBlur, onFocusCapture: handleFocus, onKeyDown: handleKeyDown, onPointerEnter: handlePointerEnter, onPointerLeave: handlePointerLeave, ref: rootRef, role: role, style: rootStyle, tabIndex: !disabled && count > 1 ? (tabIndex ?? 0) : tabIndex, children: [_jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-carousel__focus-ring", radius: 8, seed: `${generatedId}-focus`, variant: "outline" }), count === 0 ? _jsx("div", { className: "inkra-carousel__empty", children: emptyState ?? labels?.empty ?? '
|
|
299
|
+
return _jsxs("div", { ...props, "aria-label": ariaLabel, "aria-roledescription": "carousel", className: ['inkra-carousel', className].filter(Boolean).join(' '), "data-autoplay": autoplayEnabled || undefined, "data-disabled": disabled || undefined, "data-playing": playing || undefined, dir: resolvedDir, onBlurCapture: handleBlur, onFocusCapture: handleFocus, onKeyDown: handleKeyDown, onPointerEnter: handlePointerEnter, onPointerLeave: handlePointerLeave, ref: rootRef, role: role, style: rootStyle, tabIndex: !disabled && count > 1 ? (tabIndex ?? 0) : tabIndex, children: [_jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-carousel__focus-ring", radius: 8, seed: `${generatedId}-focus`, variant: "outline" }), count === 0 ? _jsx("div", { className: "inkra-carousel__empty", children: emptyState ?? labels?.empty ?? t('common.noItems') }) : _jsxs(_Fragment, { children: [_jsx("div", { className: "inkra-carousel__viewport", ref: viewportRef, children: _jsx("div", { className: "inkra-carousel__container", children: slideItems.map((item, index) => _jsx("div", { "aria-label": slideLabel(index + 1, count), "aria-roledescription": "slide", className: "inkra-carousel__slide", "data-current": index === activeIndex || undefined, role: "group", children: item }, item.key ?? index)) }) }), (showNavigation || showPagination || autoplayEnabled) && _jsxs("div", { className: "inkra-carousel__toolbar", children: [showNavigation && _jsxs("div", { className: "inkra-carousel__navigation", children: [_jsx(Button, { "aria-label": labels?.previous ?? t('carousel.previous'), disabled: disabled || !canScrollPrevious, onClick: previous, size: "icon", variant: "outline", children: _jsx(PencilIcon, { decorative: true, paths: resolvedDir === 'rtl' ? nextPaths : previousPaths, seed: `${generatedId}-previous`, size: 20, sourceSize: 24 }) }), _jsx(Button, { "aria-label": labels?.next ?? t('carousel.next'), disabled: disabled || !canScrollNext, onClick: next, size: "icon", variant: "outline", children: _jsx(PencilIcon, { decorative: true, paths: resolvedDir === 'rtl' ? previousPaths : nextPaths, seed: `${generatedId}-next`, size: 20, sourceSize: 24 }) })] }), showPagination && _jsx("div", { "aria-label": labels?.pages ?? t('carousel.pages'), className: "inkra-carousel__pagination", role: "group", children: scrollSnaps.map((_, index) => _jsxs("button", { "aria-current": index === selectedIndex ? 'true' : undefined, "aria-label": pageLabel(index + 1, scrollSnaps.length), className: "inkra-carousel__page", disabled: disabled, onClick: () => scrollTo(index), type: "button", children: [_jsx(PencilSurface, { as: "span", "aria-hidden": "true", className: "inkra-carousel__page-mark", radius: 6, seed: `${generatedId}-page-${index}`, variant: index === selectedIndex ? 'selection' : 'outline' }), _jsx(PencilSurface, { as: "span", "aria-hidden": "true", className: "inkra-carousel__page-focus", radius: 6, seed: `${generatedId}-page-${index}-focus`, variant: "outline" })] }, index)) }), autoplayEnabled && _jsx(Button, { "aria-label": playing ? (labels?.pause ?? t('carousel.pause')) : (labels?.play ?? t('carousel.play')), disabled: !autoplayAllowed, onClick: toggleAutoplay, onPointerDown: () => { autoplayControlPointerRef.current = true; }, size: "icon", variant: "ghost", children: _jsx(PencilIcon, { decorative: true, paths: playing ? pausePaths : playPaths, seed: `${generatedId}-autoplay`, size: 20, sourceSize: 24 }) })] })] }), count > 0 && _jsx("span", { "aria-atomic": "true", "aria-live": playing ? 'off' : 'polite', className: "inkra-carousel__status", children: statusLabel(activeIndex + 1, count) })] });
|
|
297
300
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import { Children, createContext, forwardRef, memo, isValidElement, useContext, useCallback, useMemo, useId, useImperativeHandle, useRef, useState, } from 'react';
|
|
3
4
|
import { Button } from '../Button.js';
|
|
4
5
|
import { PencilSurface } from '../PencilSurface.js';
|
|
@@ -27,7 +28,8 @@ function gridStyle(style, columns, minItemWidth) {
|
|
|
27
28
|
};
|
|
28
29
|
}
|
|
29
30
|
export const ChoiceGrid = memo(forwardRef(function ChoiceGrid(props, forwardedRef) {
|
|
30
|
-
const {
|
|
31
|
+
const { t } = useInkraLocale();
|
|
32
|
+
const { 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, children, className, columns, description, disabled = false, error, form, label, minItemWidth = '13rem', name, pageSize, previousPageLabel = t('common.previousPage'), nextPageLabel = t('common.nextPage'), pageLabel = (page, pages) => `${page} / ${pages}`, style, type = 'single', ...rest } = props;
|
|
31
33
|
const generatedId = useId();
|
|
32
34
|
const descriptionId = description == null ? undefined : `inkra-choice-grid-${generatedId}-description`;
|
|
33
35
|
const errorId = error == null ? undefined : `inkra-choice-grid-${generatedId}-error`;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type InkraTranslate } from '../i18n/index.js';
|
|
1
2
|
import type { ReactNode } from 'react';
|
|
2
3
|
import type { ColorGradient } from './gradient.js';
|
|
3
4
|
import type { ColorValue } from './color.js';
|
|
@@ -28,7 +29,7 @@ export interface ColorGradientLabels {
|
|
|
28
29
|
farthestCorner?: string;
|
|
29
30
|
repeating?: string;
|
|
30
31
|
}
|
|
31
|
-
export declare const defaultGradientLabels: Required<ColorGradientLabels>;
|
|
32
|
+
export declare const defaultGradientLabels: (t: InkraTranslate) => Required<ColorGradientLabels>;
|
|
32
33
|
export declare function GradientEditor({ value, disabled, maxStops, labels, onChange, renderColorEditor }: {
|
|
33
34
|
value: ColorGradient;
|
|
34
35
|
disabled: boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import {} from '../i18n/index.js';
|
|
2
3
|
import { useId, useRef, useState } from 'react';
|
|
3
4
|
import { __iconData as addIcon } from 'lucide-react/dist/esm/icons/plus.mjs';
|
|
4
5
|
import { __iconData as removeIcon } from 'lucide-react/dist/esm/icons/minus.mjs';
|
|
@@ -15,15 +16,15 @@ import { Slider } from '../slider/index.js';
|
|
|
15
16
|
import { Switch } from '../selection/Switch.js';
|
|
16
17
|
import { ToggleGroup } from '../toggle-group/index.js';
|
|
17
18
|
import { formatColorPaint } from './gradient.js';
|
|
18
|
-
export const defaultGradientLabels = {
|
|
19
|
-
type: '
|
|
20
|
-
preview: '
|
|
21
|
-
addStop: '
|
|
22
|
-
position: '
|
|
23
|
-
shape: '
|
|
24
|
-
closestSide: '
|
|
25
|
-
farthestSide: '
|
|
26
|
-
};
|
|
19
|
+
export const defaultGradientLabels = (t) => ({
|
|
20
|
+
type: t('gradient.type'), solid: t('gradient.solid'), linear: t('gradient.linear'), radial: t('gradient.radial'), conic: t('gradient.conic'),
|
|
21
|
+
preview: t('gradient.preview'), stops: t('gradient.stops'), stop: t('gradient.stop'), stopColor: t('gradient.stopColor'),
|
|
22
|
+
addStop: t('gradient.add'), removeStop: t('gradient.remove'), reverse: t('gradient.reverse'),
|
|
23
|
+
position: t('gradient.position'), angle: t('gradient.angle'), centerX: t('gradient.centerX'), centerY: t('gradient.centerY'),
|
|
24
|
+
shape: t('gradient.shape'), circle: t('gradient.circle'), ellipse: t('gradient.ellipse'), extent: t('gradient.extent'),
|
|
25
|
+
closestSide: t('gradient.closestSide'), closestCorner: t('gradient.closestCorner'),
|
|
26
|
+
farthestSide: t('gradient.farthestSide'), farthestCorner: t('gradient.farthestCorner'), repeating: t('gradient.repeat'),
|
|
27
|
+
});
|
|
27
28
|
const iconPaths = (data) => data.node.filter(([tag]) => tag === 'path').map(([, attrs]) => ({ d: attrs.d }));
|
|
28
29
|
const actions = { add: iconPaths(addIcon), remove: iconPaths(removeIcon), reverse: iconPaths(reverseIcon) };
|
|
29
30
|
export function GradientEditor({ value, disabled, maxStops, labels, onChange, renderColorEditor }) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import { useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
3
4
|
import { Button } from '../Button.js';
|
|
4
5
|
import { ColorSwatch } from '../color-swatch/index.js';
|
|
@@ -12,13 +13,13 @@ import { ToggleGroup } from '../toggle-group/index.js';
|
|
|
12
13
|
import { GradientEditor, defaultGradientLabels } from './GradientEditor.js';
|
|
13
14
|
import { colorPaintTypes, createColorGradient, formatColorPaint, normalizeColorPaint } from './gradient.js';
|
|
14
15
|
import { DEFAULT_COLOR_VALUE, colorAlphaPercent, colorRgbValue, normalizeColorValue, withColorAlpha, withColorRgb, } from './color.js';
|
|
15
|
-
const defaultLabels = {
|
|
16
|
-
palette: '
|
|
17
|
-
value: '
|
|
18
|
-
alpha: '
|
|
19
|
-
presets: '
|
|
20
|
-
invalid: '
|
|
21
|
-
};
|
|
16
|
+
const defaultLabels = (t) => ({
|
|
17
|
+
palette: t('color.palette'),
|
|
18
|
+
value: t('color.value'),
|
|
19
|
+
alpha: t('color.alpha'),
|
|
20
|
+
presets: t('color.presets'),
|
|
21
|
+
invalid: t('color.invalid'),
|
|
22
|
+
});
|
|
22
23
|
function presetData(preset, allowGradient) {
|
|
23
24
|
const input = typeof preset === 'string' ? preset : preset.value;
|
|
24
25
|
const value = typeof input === 'string' || allowGradient ? normalizeColorPaint(input) : null;
|
|
@@ -27,7 +28,8 @@ function presetData(preset, allowGradient) {
|
|
|
27
28
|
return { value, label: typeof preset === 'string' ? preset : preset.label ?? formatColorPaint(value) };
|
|
28
29
|
}
|
|
29
30
|
export function ColorPicker(options) {
|
|
30
|
-
const {
|
|
31
|
+
const { t } = useInkraLocale();
|
|
32
|
+
const { allowGradient = false, colorTypes = colorPaintTypes, maxStops = 8, gradientLabels, className, defaultValue = DEFAULT_COLOR_VALUE, disabled = false, form, id, label = t('color.label'), labels, name, onInvalidInput, onValueChange: _onValueChange, presets = [], presentation = 'inline', seed, showAlpha = true, value, ...props } = options;
|
|
31
33
|
const generatedId = useId();
|
|
32
34
|
const resolvedId = id ?? `inkra-color-picker-${generatedId}`;
|
|
33
35
|
const resolvedSeed = seed ?? resolvedId;
|
|
@@ -54,8 +56,8 @@ export function ColorPicker(options) {
|
|
|
54
56
|
const skipNextBlurRef = useRef(false);
|
|
55
57
|
const [draft, setDraft] = useState(currentColor);
|
|
56
58
|
const [open, setOpen] = useState(false);
|
|
57
|
-
const copy = { ...defaultLabels, ...labels };
|
|
58
|
-
const gradientCopy = { ...defaultGradientLabels, ...gradientLabels };
|
|
59
|
+
const copy = { ...defaultLabels(t), ...labels };
|
|
60
|
+
const gradientCopy = { ...defaultGradientLabels(t), ...gradientLabels };
|
|
59
61
|
const parsedPresets = useMemo(() => presets.map(preset => presetData(preset, allowGradient)).filter((preset) => preset !== null), [presets, allowGradient]);
|
|
60
62
|
const inputInvalid = normalizeColorValue(draft) === null;
|
|
61
63
|
const rgbValue = colorRgbValue(currentColor) ?? '#4b96aa';
|
package/dist/content/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
|
3
4
|
import { createContext, useContext, forwardRef, useId, useState } from 'react';
|
|
4
5
|
import { Button } from '../Button.js';
|
|
@@ -31,7 +32,9 @@ const CardFooter = forwardRef(function CardFooter({ className, children, divided
|
|
|
31
32
|
return _jsxs("div", { ...props, ref: ref, "data-justify": justify, "data-padding": padding, "data-orientation": orientation, className: classes('inkra-card__footer', className), children: [(divided ?? inherited) && _jsx(PencilLine, { className: "inkra-card__divider" }), children] });
|
|
32
33
|
});
|
|
33
34
|
export const Card = { Root: CardRoot, Header: CardHeader, Title: CardTitle, Description: CardDescription, Content: CardContent, Footer: CardFooter };
|
|
34
|
-
const AlertRoot = forwardRef(function AlertRoot(
|
|
35
|
+
const AlertRoot = forwardRef(function AlertRoot(inkraProps, ref) {
|
|
36
|
+
const { t } = useInkraLocale();
|
|
37
|
+
const { className, variant = 'info', icon, seed, style, children, role = 'status', size = 'md', appearance = 'soft', actions, closable = false, open, defaultOpen = true, onOpenChange, closeLabel = t('alert.dismiss'), ...props } = inkraProps;
|
|
35
38
|
const id = useId();
|
|
36
39
|
const [internalOpen, setInternalOpen] = useState(defaultOpen);
|
|
37
40
|
if (!(open ?? internalOpen))
|
|
@@ -50,4 +50,4 @@ export interface DataTableProps<TData> extends Omit<HTMLAttributes<HTMLDivElemen
|
|
|
50
50
|
pageLabel?: (page: number, pageCount: number) => ReactNode;
|
|
51
51
|
sortStatusLabel?: (columnId: string, direction: false | 'asc' | 'desc') => string;
|
|
52
52
|
}
|
|
53
|
-
export declare function DataTable<TData>(
|
|
53
|
+
export declare function DataTable<TData>(inkraProps: DataTableProps<TData>): import("react").JSX.Element;
|
package/dist/data-table/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import { flexRender, functionalUpdate, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table';
|
|
3
4
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
4
5
|
import { Button } from '../Button.js';
|
|
@@ -28,7 +29,9 @@ function pencilCopy(value, seed) {
|
|
|
28
29
|
function SelectionCheckbox(props) {
|
|
29
30
|
return _jsx(Checkbox, { className: "inkra-data-table__selection", checked: props.checked, indeterminate: props.indeterminate, disabled: props.disabled, label: _jsx("span", { className: "inkra-visually-hidden", children: props.label }), onCheckedChange: props.onChange });
|
|
30
31
|
}
|
|
31
|
-
export function DataTable(
|
|
32
|
+
export function DataTable(inkraProps) {
|
|
33
|
+
const { t } = useInkraLocale();
|
|
34
|
+
const { data, columns, getRowId, caption, density = 'comfortable', layout = 'auto', striped = false, hoverable = true, stickyHeader = false, captionSide = 'top', filterable = false, filterLabel = t('table.filter'), filterPlaceholder = t('table.filter'), globalFilter, defaultGlobalFilter = '', onGlobalFilterChange, sorting, defaultSorting = [], onSortingChange, pagination = false, manualPagination = false, rowCount, manualSorting = false, manualFiltering = false, paginationState, defaultPagination = { pageIndex: 0, pageSize: 10 }, onPaginationChange, selectable = false, rowSelection, defaultRowSelection = {}, onRowSelectionChange, getRowCanSelect, loading = false, loadingMessage = t('table.loading'), emptyMessage = t('table.empty'), selectAllLabel = t('table.selectAll'), selectRowLabel = row => t('table.selectRow', { row: row.id }), previousPageLabel = t('common.previousPage'), nextPageLabel = t('common.nextPage'), paginationLabel = t('table.pagination'), pageLabel = (page, pageCount) => t('pagination.status', { page, total: pageCount }), sortStatusLabel = (columnId, direction) => t(direction === 'asc' ? 'table.ascending' : direction === 'desc' ? 'table.descending' : 'table.unsorted', { column: columnId }), className, ...props } = inkraProps;
|
|
32
35
|
const [internalFilter, setInternalFilter] = useState(defaultGlobalFilter);
|
|
33
36
|
const [internalSorting, setInternalSorting] = useState(defaultSorting);
|
|
34
37
|
const [internalPagination, setInternalPagination] = useState(defaultPagination);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale, resolveInkraLocale } from '../i18n/index.js';
|
|
3
|
+
import { calendarLocales } from '../calendar/locales.js';
|
|
2
4
|
import { forwardRef, useEffect, useId, useImperativeHandle, useMemo, useRef, useState, } from 'react';
|
|
3
5
|
import { Button, ButtonGroup } from '../Button.js';
|
|
4
6
|
import { Calendar } from '../calendar/index.js';
|
|
@@ -35,24 +37,19 @@ function initialForMode(mode, value) {
|
|
|
35
37
|
return validDate(value) ? value : undefined;
|
|
36
38
|
return isRange(value) ? value : undefined;
|
|
37
39
|
}
|
|
38
|
-
function defaultCopy(
|
|
39
|
-
const chinese = locale.toLowerCase().startsWith('zh');
|
|
40
|
+
function defaultCopy(t) {
|
|
40
41
|
return {
|
|
41
|
-
calendar:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
placeholder: chinese ? '选择日期' : 'Choose a date',
|
|
46
|
-
previous: chinese ? '上个月' : 'Previous month',
|
|
47
|
-
rangePlaceholder: chinese ? '选择日期范围' : 'Choose a date range',
|
|
48
|
-
selected: chinese ? '已选择' : 'selected',
|
|
49
|
-
today: chinese ? '今天' : 'today',
|
|
42
|
+
calendar: t('datePicker.calendar'), clear: t('datePicker.clear'),
|
|
43
|
+
next: t('datePicker.next'), open: t('datePicker.open'),
|
|
44
|
+
placeholder: t('datePicker.placeholder'), previous: t('datePicker.previous'),
|
|
45
|
+
rangePlaceholder: t('datePicker.range'), selected: t('datePicker.selected'), today: t('datePicker.today'),
|
|
50
46
|
};
|
|
51
47
|
}
|
|
52
48
|
export const DatePicker = forwardRef(function DatePicker(allProps, forwardedRef) {
|
|
53
49
|
const valueControlled = Object.prototype.hasOwnProperty.call(allProps, 'value');
|
|
54
50
|
const openControlled = Object.prototype.hasOwnProperty.call(allProps, 'open');
|
|
55
|
-
const { 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage, 'aria-invalid': ariaInvalid, 'aria-label': ariaLabel, autoFocus, calendarLabel, calendarProps = {}, className, clearable = true, clearButtonLabel, defaultOpen = false, defaultValue, dir, disabled = false, endName, form, fullWidth = true, id, invalid = false, locale
|
|
51
|
+
const { 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage, 'aria-invalid': ariaInvalid, 'aria-label': ariaLabel, autoFocus, calendarLabel, calendarProps = {}, className, clearable = true, clearButtonLabel, defaultOpen = false, defaultValue, dir, disabled = false, endName, form, fullWidth = true, id, invalid = false, locale: localeProp, mode = 'single', name, onBlur, onFocus, onOpenChange, onValueChange, open, openButtonLabel, placeholder, rangeSeparator = ' – ', readOnly = false, required = false, size = 'md', style, value, } = allProps;
|
|
52
|
+
const { locale, t } = useInkraLocale(localeProp);
|
|
56
53
|
const generatedId = useId();
|
|
57
54
|
const field = useFieldContext();
|
|
58
55
|
const triggerRef = useRef(null);
|
|
@@ -71,7 +68,7 @@ export const DatePicker = forwardRef(function DatePicker(allProps, forwardedRef)
|
|
|
71
68
|
'aria-errormessage': ariaErrorMessage,
|
|
72
69
|
'aria-invalid': ariaInvalid,
|
|
73
70
|
});
|
|
74
|
-
const copy = defaultCopy(
|
|
71
|
+
const copy = defaultCopy(t);
|
|
75
72
|
const currentValue = initialForMode(mode, valueControlled ? value : uncontrolledValue);
|
|
76
73
|
const currentOpen = openControlled ? Boolean(open) : uncontrolledOpen;
|
|
77
74
|
const singleValue = validDate(currentValue) ? currentValue : undefined;
|
|
@@ -144,6 +141,7 @@ export const DatePicker = forwardRef(function DatePicker(allProps, forwardedRef)
|
|
|
144
141
|
...labels,
|
|
145
142
|
};
|
|
146
143
|
const sharedCalendarProps = {
|
|
144
|
+
locale: calendarLocales[resolveInkraLocale(locale)],
|
|
147
145
|
...restCalendarProps,
|
|
148
146
|
appearance: 'picker',
|
|
149
147
|
defaultMonth: defaultMonth ?? firstDate,
|
|
@@ -45,4 +45,4 @@ export declare function agendaInterval(event: AgendaEvent): {
|
|
|
45
45
|
before: boolean;
|
|
46
46
|
after: boolean;
|
|
47
47
|
} | null;
|
|
48
|
-
export declare function DayAgenda(
|
|
48
|
+
export declare function DayAgenda(inkraProps: DayAgendaProps): import("react").JSX.Element;
|