@inkra/react 0.4.3 → 0.5.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 +98 -0
- package/dist/audio-player/index.js +6 -4
- package/dist/breadcrumb/index.js +4 -1
- 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 +4 -1
- package/dist/sortable/index.js +11 -9
- package/dist/sparkline/index.js +7 -7
- package/dist/steps/index.js +4 -1
- package/dist/styles/select.css +1 -4
- package/dist/styles.css +1 -4
- 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.
|
|
@@ -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]));
|
package/dist/breadcrumb/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
2
3
|
import { forwardRef } from 'react';
|
|
3
4
|
import { ButtonLink } from '../Button.js';
|
|
4
5
|
import { PencilText } from '../PencilText.js';
|
|
5
6
|
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
6
7
|
const copy = (children) => typeof children === 'string' ? _jsx(PencilText, { children: children }) : children;
|
|
7
|
-
const Root = forwardRef(function BreadcrumbRoot(
|
|
8
|
+
const Root = forwardRef(function BreadcrumbRoot(inkraProps, ref) {
|
|
9
|
+
const { t } = useInkraLocale();
|
|
10
|
+
const { className, 'aria-label': label = t('breadcrumb.label'), ...props } = inkraProps;
|
|
8
11
|
return _jsx("nav", { ...props, ref: ref, "aria-label": label, className: classes('inkra-breadcrumb', className) });
|
|
9
12
|
});
|
|
10
13
|
const List = forwardRef(function BreadcrumbList({ className, ...props }, ref) {
|
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;
|
package/dist/day-agenda/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useId, useMemo, useState } from 'react';
|
|
3
|
+
import { useInkraLocale } from '../i18n/index.js';
|
|
3
4
|
import { TravelIcon } from '../internal/travelIcons.js';
|
|
4
5
|
import { Button } from '../Button.js';
|
|
5
6
|
import { createAgendaScale, layoutAgendaCards } from './layout.js';
|
|
@@ -29,7 +30,9 @@ export function agendaInterval(event) {
|
|
|
29
30
|
return null;
|
|
30
31
|
return { start: Math.max(0, event.startMinute), end: Math.min(1440, end ?? event.startMinute), before: event.startMinute < 0, after: (end ?? 0) > 1440 };
|
|
31
32
|
}
|
|
32
|
-
export function DayAgenda(
|
|
33
|
+
export function DayAgenda(inkraProps) {
|
|
34
|
+
const { locale, t } = useInkraLocale(inkraProps.locale);
|
|
35
|
+
const { date, events, selectedEvent, onEventSelect, locale: _locale, timeZoneLabel, emptyLabel = t('agenda.empty'), untimedLabel = t('agenda.pending'), showOverview = true, hourCycle = 'h23', density = 'comfortable', showDescriptions = true, divided = true, disabled = false, onPreviousDay, onNextDay, navigationLabels = { previous: t('agenda.previous'), next: t('agenda.next') }, maxVisibleEvents, showAllEventsLabel = count => t('agenda.all', { count }), showFewerEventsLabel = t('agenda.fewer'), className, ...props } = inkraProps;
|
|
33
36
|
const id = useId();
|
|
34
37
|
const [expandedDate, setExpandedDate] = useState();
|
|
35
38
|
const displayLimit = maxVisibleEvents !== undefined && Number.isFinite(maxVisibleEvents) ? Math.max(0, Math.floor(maxVisibleEvents)) : Infinity;
|
|
@@ -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 { DndContext, MouseSensor, TouchSensor, useDraggable, useSensor, useSensors, } from '@dnd-kit/core';
|
|
3
4
|
import { createContext, forwardRef, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, } from 'react';
|
|
4
5
|
import { Button } from '../Button.js';
|
|
@@ -96,13 +97,13 @@ const resetPaths = [
|
|
|
96
97
|
{ d: 'M4 12a8 8 0 1 0 2.34-5.66L4 8.68' },
|
|
97
98
|
{ d: 'M4 4v4.68h4.68' },
|
|
98
99
|
];
|
|
99
|
-
const defaultLabels = {
|
|
100
|
-
move: '
|
|
101
|
-
collapse: '
|
|
102
|
-
expand: '
|
|
103
|
-
reset: '
|
|
104
|
-
keyboardInstructions: '
|
|
105
|
-
};
|
|
100
|
+
const defaultLabels = (t) => ({
|
|
101
|
+
move: t('dockable.move'),
|
|
102
|
+
collapse: t('dockable.collapse'),
|
|
103
|
+
expand: t('dockable.expand'),
|
|
104
|
+
reset: t('dockable.reset'),
|
|
105
|
+
keyboardInstructions: t('dockable.instructions'),
|
|
106
|
+
});
|
|
106
107
|
function renderTitle(title) {
|
|
107
108
|
return typeof title === 'string' ? _jsx(PencilText, { children: title }) : title;
|
|
108
109
|
}
|
|
@@ -110,6 +111,7 @@ function isInteractiveTarget(target) {
|
|
|
110
111
|
return target instanceof Element && Boolean(target.closest('button, a, input, select, textarea, [contenteditable="true"], [data-dockable-panel-no-drag]'));
|
|
111
112
|
}
|
|
112
113
|
export const DockablePanel = forwardRef(function DockablePanel({ children, className, collapsed, collapsible = true, defaultCollapsed = false, defaultPosition = { x: 8, y: 8 }, headerActions, id, keyboardStep = 8, labels: labelOverrides, movable = true, onCollapsedChange, onFocusCapture, onPointerDown, onPositionChange, position, style, title, ...props }, forwardedRef) {
|
|
114
|
+
const { t } = useInkraLocale();
|
|
113
115
|
const workspace = useContext(WorkspaceContext);
|
|
114
116
|
if (!workspace)
|
|
115
117
|
throw new Error('DockablePanel must be rendered inside DockablePanelWorkspace.');
|
|
@@ -125,7 +127,7 @@ export const DockablePanel = forwardRef(function DockablePanel({ children, class
|
|
|
125
127
|
const resolvedCollapsed = collapsed ?? uncontrolledCollapsed;
|
|
126
128
|
const positionRef = useRef(resolvedPosition);
|
|
127
129
|
positionRef.current = resolvedPosition;
|
|
128
|
-
const labels = { ...defaultLabels, ...labelOverrides };
|
|
130
|
+
const labels = { ...defaultLabels(t), ...labelOverrides };
|
|
129
131
|
const { activate, bounds, commitDrag, layer, register, snapThreshold, } = workspace;
|
|
130
132
|
const { attributes, isDragging, listeners, setActivatorNodeRef, setNodeRef, transform } = useDraggable({
|
|
131
133
|
id,
|
package/dist/drawer/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 DialogPrimitive from '@radix-ui/react-dialog';
|
|
3
4
|
import { forwardRef, useId } from 'react';
|
|
4
5
|
import { __iconData as closeIcon } from 'lucide-react/dist/esm/icons/x.mjs';
|
|
@@ -53,7 +54,9 @@ export const DrawerDescription = forwardRef(function DrawerDescription({ childre
|
|
|
53
54
|
export const DrawerClose = forwardRef(function DrawerClose(props, ref) {
|
|
54
55
|
return _jsx(DialogPrimitive.Close, { ...props, ref: ref });
|
|
55
56
|
});
|
|
56
|
-
export const DrawerCloseButton = forwardRef(function DrawerCloseButton(
|
|
57
|
+
export const DrawerCloseButton = forwardRef(function DrawerCloseButton(inkraProps, ref) {
|
|
58
|
+
const { t } = useInkraLocale();
|
|
59
|
+
const { className, label = t('common.close'), onFocus, ...props } = inkraProps;
|
|
57
60
|
return _jsx(Tooltip.Provider, { children: _jsxs(Tooltip.Root, { children: [_jsx(Tooltip.Trigger, { asChild: true, children: _jsx(DialogPrimitive.Close, { asChild: true, children: _jsx(Button, { ...props, "aria-label": label, className: classes('inkra-drawer__close-button', className), ref: ref, size: "icon", type: "button", variant: "outline", onFocus: event => {
|
|
58
61
|
onFocus?.(event);
|
|
59
62
|
const dialog = event.currentTarget.closest('[role="dialog"]');
|
|
@@ -61,7 +64,9 @@ export const DrawerCloseButton = forwardRef(function DrawerCloseButton({ classNa
|
|
|
61
64
|
event.preventDefault();
|
|
62
65
|
}, children: _jsx(PencilIcon, { decorative: true, paths: closePaths, size: 30, sourceSize: 24 }) }) }) }), _jsx(Tooltip.Portal, { children: _jsx(Tooltip.Content, { align: "end", side: "bottom", children: label }) })] }) });
|
|
63
66
|
});
|
|
64
|
-
export const DrawerHeader = forwardRef(function DrawerHeader(
|
|
67
|
+
export const DrawerHeader = forwardRef(function DrawerHeader(inkraProps, ref) {
|
|
68
|
+
const { t } = useInkraLocale();
|
|
69
|
+
const { action, children, className, closeLabel = t('common.close'), divided = true, showClose = true, ...props } = inkraProps;
|
|
65
70
|
const id = useId();
|
|
66
71
|
const hasActions = Boolean(action || showClose);
|
|
67
72
|
return _jsxs("div", { ...props, className: classes('inkra-drawer__header', className), "data-actions": hasActions || undefined, "data-custom-action": action ? true : undefined, "data-divided": divided || undefined, ref: ref, children: [_jsx("div", { className: "inkra-drawer__heading", children: children }), hasActions ? _jsxs("div", { className: "inkra-drawer__header-actions", children: [action, showClose ? _jsx(DrawerCloseButton, { label: closeLabel }) : null] }) : null, divided ? _jsx(PencilLine, { className: "inkra-drawer__divider", seed: `drawer-header-${id}` }) : null] });
|