@inkra/react 0.2.0 → 0.3.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 +86 -4
- package/dist/alert-dialog/index.d.ts +1 -1
- package/dist/alert-dialog/index.js +4 -2
- package/dist/command/index.d.ts +24 -2
- package/dist/command/index.js +2 -2
- package/dist/context-menu/index.d.ts +2 -2
- package/dist/context-menu/index.js +3 -2
- package/dist/drawer/index.d.ts +1 -1
- package/dist/drawer/index.js +6 -4
- package/dist/dropdown-menu/index.d.ts +1 -1
- package/dist/dropdown-menu/index.js +3 -2
- package/dist/form/EditablePencilText.js +34 -0
- package/dist/form/Input.js +1 -1
- package/dist/input-number/index.d.ts +6 -0
- package/dist/input-number/index.js +126 -15
- package/dist/input-number/model.d.ts +13 -0
- package/dist/input-number/model.js +50 -0
- package/dist/number-ticker/index.d.ts +11 -9
- package/dist/number-ticker/index.js +14 -11
- package/dist/number-ticker/model.d.ts +38 -5
- package/dist/number-ticker/model.js +139 -10
- package/dist/number-ticker/precision.d.ts +7 -0
- package/dist/number-ticker/precision.js +134 -0
- package/dist/overlay/Overlay.d.ts +1 -1
- package/dist/overlay/Overlay.js +4 -2
- package/dist/overlay/Popover.d.ts +1 -1
- package/dist/overlay/Popover.js +3 -2
- package/dist/overlay/themeBridge.d.ts +12 -1
- package/dist/overlay/themeBridge.js +27 -1
- package/dist/radar/index.d.ts +2 -0
- package/dist/radar/index.js +2 -2
- package/dist/sortable/index.js +9 -4
- package/dist/styles.css +147 -22
- package/dist/tooltip/Tooltip.d.ts +1 -1
- package/dist/tooltip/Tooltip.js +3 -2
- package/dist/virtual-list/index.js +3 -2
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Inkra
|
|
2
2
|
|
|
3
|
-
Inkra is a pencil-styled React component library. It includes action, form, overlay, navigation, content and feedback components, plus Calendar, DayAgenda, JourneyMap and deterministic drawing primitives.
|
|
3
|
+
Inkra is a pencil-styled React component library. It includes action, form, overlay, navigation, content and feedback components, plus Calendar, DayAgenda, JourneyMap and deterministic drawing primitives. This document describes the APIs shipped with this package; see the repository changelog and npm registry for release status.
|
|
4
4
|
|
|
5
5
|
Source and maintenance: [inkrajs/inkra](https://github.com/inkrajs/inkra).
|
|
6
6
|
|
|
@@ -80,6 +80,18 @@ All standard `button` props, including `disabled`, `name`, `value`, `form`, `ari
|
|
|
80
80
|
|
|
81
81
|
`InputNumber` places decrease and increase buttons on either side of a centered numeric input, with no clear button. Keyboard deletion produces `null`; decimal stepping and out-of-range validation remain native. `Slider` supports single/range values, horizontal/vertical layout and `standard` or `inset` appearance.
|
|
82
82
|
|
|
83
|
+
`InputNumber` supports Shift-click and Shift-arrow increments of 10 by default.
|
|
84
|
+
Use `stepModifiers={[{ shiftKey: true, step: 10 }, { altKey: true, step: 0.1 }]}`
|
|
85
|
+
to configure exact modifier chords with absolute increments, or `[]` to disable
|
|
86
|
+
overrides. The first valid matching rule wins; unspecified modifiers must be
|
|
87
|
+
released. Values remain bounded by `min`/`max`; `step="any"` disables stepping.
|
|
88
|
+
`pressAndHold` defaults to true, with `repeatDelay={400}` and
|
|
89
|
+
`repeatInterval={80}` in milliseconds. Release, cancellation, blur, backgrounding,
|
|
90
|
+
disabling and value boundaries stop repetition. Delay/interval are bounded to
|
|
91
|
+
150-60000/32-60000 ms. Numeric values use pencil lettering at rest and during
|
|
92
|
+
button stepping. Direct text entry deliberately stays native until blur, keeping
|
|
93
|
+
browser-owned incomplete drafts such as `-`, `1.` and `1e` readable.
|
|
94
|
+
|
|
83
95
|
`Select.Root` uses string values for single selection and string arrays with `multiple`. Multi-select remains open while toggling items and submits repeated values under the same field name. `Select.Clear` is a separate button; never nest it inside the trigger.
|
|
84
96
|
|
|
85
97
|
`Select.Trigger` supports `startIcon`, `endIcon`, `hideValue`, `hideIndicator`, `iconOnly`, `fullWidth` and `textAlign`. The existing `icon` prop replaces the dropdown indicator. Icon-only mode keeps a square hit target of at least 44px and retains selected text as an accessible description. Provide a Field/ARIA name and Tooltip for icon-only triggers. Decorative slots must not contain interactive controls.
|
|
@@ -195,10 +207,9 @@ Content layout options preserve existing defaults:
|
|
|
195
207
|
- `Avatar.Root.radius` clamps to 0-8px, including pencil and image corners; `bordered={false}` removes the outline. `Avatar.Image.fit` accepts `cover | contain` (default cover).
|
|
196
208
|
- `Table.Root.striped`, `hoverable` and `stickyHeader` default to false. Constrain `Table.Container` with `style={{ maxHeight: 240 }}` for sticky scrolling. `captionSide` accepts `top | bottom`. `Head.align` and `Cell.align` accept logical `start | center | end`, retaining native alignment values for compatibility. Hover feedback does not imply row actions.
|
|
197
209
|
|
|
198
|
-
##
|
|
210
|
+
## Additional Components
|
|
199
211
|
|
|
200
|
-
These exports
|
|
201
|
-
install the local candidate to use them. The documentation playground includes
|
|
212
|
+
These exports extend the original core component set. The documentation playground includes
|
|
202
213
|
working examples, live property tabs and per-component API/accessibility notes.
|
|
203
214
|
|
|
204
215
|
| Component | Contract |
|
|
@@ -239,6 +250,77 @@ motion and SSR show deterministic final values. Intermediate frames are visual;
|
|
|
239
250
|
the polite announcement updates only at the final value. Use `getValueLabel`
|
|
240
251
|
when units or custom rendering need a complete accessible phrase.
|
|
241
252
|
|
|
253
|
+
Set `compact` to follow `locale` (Chinese units for `zh`, English units otherwise),
|
|
254
|
+
or use `compact="en"` / `compact="zh"` to select a unit table explicitly.
|
|
255
|
+
English uses this library's short-scale suffix convention: K, M, B, T, Qa, Qi,
|
|
256
|
+
Sx, Sp, Oc, No, Dc (10^3 through 10^33, increasing by 10^3).
|
|
257
|
+
Chinese uses 千 (10^3), then 万, 亿, 兆, 京, 垓, 秭, 穰, 沟, 涧, 正, 载, 极,
|
|
258
|
+
恒河沙, 阿僧祇, 那由他, 不可思议, 无量大数 (10^4 through 10^68, increasing by 10^4).
|
|
259
|
+
`numberTickerUnits` exports both tables. A space separates numbers and units by default.
|
|
260
|
+
The default is `false`, preserving existing `formatOptions` behavior. Compact mode
|
|
261
|
+
uses at most one fractional digit by default; customize precision with
|
|
262
|
+
`formatOptions`. Explicit scientific/engineering notation takes priority over compact.
|
|
263
|
+
Currency/percent affixes are preserved. By default rounding can promote the unit
|
|
264
|
+
(999,950 becomes 1 M). Deltas use the same unit
|
|
265
|
+
system with their own precision; announcements and `getValueLabel` receive the
|
|
266
|
+
unabbreviated formatted value. `renderValue` receives the abbreviated value in
|
|
267
|
+
`details.formattedValue`. NumberTicker never changes the supplied numeric value.
|
|
268
|
+
|
|
269
|
+
`compactOptions` supports:
|
|
270
|
+
|
|
271
|
+
- `minUnit` / `maxUnit`: allowed unit labels; equal bounds fix the unit. An empty
|
|
272
|
+
label denotes the unitless base. For example `maxUnit: '万'` keeps 10^8 as `10,000 万`.
|
|
273
|
+
- `separator`: defaults to one space; `''` removes it.
|
|
274
|
+
- `promotionThreshold`: positive multiplier on each unit's factor (default 1).
|
|
275
|
+
Set 10 to wait until 10,000 before entering K. `promoteAfterRounding: false`
|
|
276
|
+
compares raw magnitudes instead of rounded current-unit values.
|
|
277
|
+
- `units`: replace the table with `{ factor, label, threshold? }` entries.
|
|
278
|
+
`threshold` overrides the multiplier with an absolute display-magnitude trigger;
|
|
279
|
+
e.g. `{ factor: 10000, label: '万', threshold: 100000 }`. Binary factors work too.
|
|
280
|
+
Entries are sorted without mutation; labels/factors must be unique, factors > 1,
|
|
281
|
+
and thresholds positive, finite and strictly increasing. Invalid configurations
|
|
282
|
+
and unknown/reversed bounds throw RangeError. The unitless base is implicit.
|
|
283
|
+
- `overflow`: `unit` keeps the largest permitted unit; `scientific` switches at
|
|
284
|
+
the next unit's threshold (or extrapolates the last step at the table end).
|
|
285
|
+
Explicit `maxUnit` defaults to `unit`; otherwise the default is `scientific`.
|
|
286
|
+
|
|
287
|
+
Use `formatOptions.notation: 'scientific' | 'engineering'` for exponent notation.
|
|
288
|
+
`maximumFractionDigits` controls decimals, `minimumFractionDigits` pads zeros,
|
|
289
|
+
and `roundingMode: 'trunc'` truncates instead of rounding (`halfExpand` is default).
|
|
290
|
+
Other Intl rounding modes are supported when provided by the runtime; unsupported
|
|
291
|
+
nondefault rounding modes throw rather than silently round differently.
|
|
292
|
+
`value`, unit `factor` / `threshold`, and `promotionThreshold` accept
|
|
293
|
+
`number | bigint | string`. Use bigint for exact integers and decimal strings for
|
|
294
|
+
exact fractions or exponents beyond JavaScript's numeric range. Already-rounded
|
|
295
|
+
`number` inputs cannot regain lost digits. Decimal arithmetic uses an isolated
|
|
296
|
+
`decimal.js` context without modifying the application's Decimal settings.
|
|
297
|
+
|
|
298
|
+
```tsx
|
|
299
|
+
<NumberTicker value={9007199254740993n} showDelta />
|
|
300
|
+
<NumberTicker value="12345678901234567890.123456" formatOptions={{ maximumFractionDigits: 6 }} />
|
|
301
|
+
<NumberTicker value="1.23456789e1000" formatOptions={{ notation: 'scientific' }} />
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Strings accept signs, decimal points, e/E exponents and outer whitespace, but
|
|
305
|
+
not grouping separators, hex, empty strings or non-finite spellings. Inputs are
|
|
306
|
+
bounded to 10,000 coefficient digits and written/normalized exponents within
|
|
307
|
+
-10,000..10,000; invalid or oversized exact inputs throw `RangeError`. Decimal
|
|
308
|
+
fractions require exact Intl decimal-string support in the runtime; unsupported
|
|
309
|
+
engines throw rather than silently lose precision. Native number NaN/Infinity
|
|
310
|
+
formatting is unchanged.
|
|
311
|
+
|
|
312
|
+
`renderValue` and `getValueLabel` retain the input type; prefer the supplied
|
|
313
|
+
formatted text when custom rendering. Deltas between bigints are bigint, between
|
|
314
|
+
numbers are number, and mixed/string deltas are exact decimal strings. Bigint
|
|
315
|
+
animation frames stay integral. Input-type changes or exact arithmetic spanning
|
|
316
|
+
more than 512 digits settle immediately, as do reduced-motion updates.
|
|
317
|
+
`createNumberFormatter` remains a native Intl formatter; use
|
|
318
|
+
`formatTickerValue(formatter, value)` for precise numeric-string formatting.
|
|
319
|
+
|
|
320
|
+
`prefix` and `suffix` accept icons, text or fragments. Pass `PencilIcon` to keep
|
|
321
|
+
the library material, and `getValueLabel` to describe icon meanings to assistive
|
|
322
|
+
technology; decorative affixes are not announced twice.
|
|
323
|
+
|
|
242
324
|
`Log` renders caller-ordered records with stable ids, optional level filters and
|
|
243
325
|
pause/follow controls. It follows only append updates while the viewport remains
|
|
244
326
|
near the bottom. The named scroll region supports Home/End and intentionally is
|
|
@@ -11,7 +11,7 @@ export declare function AlertDialogRoot({ defaultOpen, onOpenChange, open, pendi
|
|
|
11
11
|
export type AlertDialogTriggerProps = DialogPrimitive.DialogTriggerProps;
|
|
12
12
|
export declare const AlertDialogTrigger: import("react").ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
13
13
|
export type AlertDialogPortalProps = DialogPrimitive.DialogPortalProps;
|
|
14
|
-
export declare function AlertDialogPortal({ children, ...props }: AlertDialogPortalProps):
|
|
14
|
+
export declare function AlertDialogPortal({ children, ...props }: AlertDialogPortalProps): ReactNode;
|
|
15
15
|
export type AlertDialogBackdropProps = DialogPrimitive.DialogOverlayProps;
|
|
16
16
|
export declare const AlertDialogBackdrop: import("react").ForwardRefExoticComponent<DialogPrimitive.DialogOverlayProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
17
17
|
export interface AlertDialogContentProps extends DialogPrimitive.DialogContentProps {
|
|
@@ -5,7 +5,7 @@ import { Button } from '../Button.js';
|
|
|
5
5
|
import { PencilLine } from '../PencilLine.js';
|
|
6
6
|
import { PencilSurface } from '../PencilSurface.js';
|
|
7
7
|
import { PencilText } from '../PencilText.js';
|
|
8
|
-
import {
|
|
8
|
+
import { mapPortalChildren, PortalThemeProvider, usePortalThemeProps, usePortalTriggerRef, } from '../overlay/themeBridge.js';
|
|
9
9
|
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
10
10
|
function assignRef(ref, value) {
|
|
11
11
|
if (typeof ref === 'function')
|
|
@@ -32,15 +32,17 @@ export const AlertDialogTrigger = forwardRef(function AlertDialogTrigger(props,
|
|
|
32
32
|
return _jsx(DialogPrimitive.Trigger, { ...props, ref: usePortalTriggerRef(forwardedRef) });
|
|
33
33
|
});
|
|
34
34
|
export function AlertDialogPortal({ children, ...props }) {
|
|
35
|
-
return (_jsx(DialogPrimitive.Portal, { ...props, children:
|
|
35
|
+
return mapPortalChildren(children, child => _jsx(DialogPrimitive.Portal, { ...props, children: child }));
|
|
36
36
|
}
|
|
37
37
|
export const AlertDialogBackdrop = forwardRef(function AlertDialogBackdrop({ className, ...props }, ref) {
|
|
38
|
+
props = usePortalThemeProps(props);
|
|
38
39
|
return (_jsx(DialogPrimitive.Overlay, { ...props, className: classes('inkra-alert-dialog__backdrop', className), ref: ref }));
|
|
39
40
|
});
|
|
40
41
|
export const AlertDialogContent = forwardRef(function AlertDialogContent({ children, className, onEscapeKeyDown, onInteractOutside, onOpenAutoFocus, onPointerDownOutside, seed, ...props }, forwardedRef) {
|
|
41
42
|
const context = useContext(AlertDialogContext);
|
|
42
43
|
const contentRef = useRef(null);
|
|
43
44
|
const id = useId();
|
|
45
|
+
props = usePortalThemeProps(props);
|
|
44
46
|
return (_jsx(DialogPrimitive.Content, { ...props, role: "alertdialog", "aria-busy": context?.pending || undefined, className: classes('inkra-alert-dialog__content', className), "data-pending": context?.pending || undefined, ref: node => {
|
|
45
47
|
contentRef.current = node;
|
|
46
48
|
assignRef(forwardedRef, node);
|
package/dist/command/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Command as Primitive } from 'cmdk';
|
|
2
2
|
import type { ComponentPropsWithoutRef, HTMLAttributes, ReactNode } from 'react';
|
|
3
|
-
export type CommandRootProps = Omit<ComponentPropsWithoutRef<typeof Primitive>, 'asChild'
|
|
3
|
+
export type CommandRootProps = Omit<ComponentPropsWithoutRef<typeof Primitive>, 'asChild'> & {
|
|
4
|
+
/** Disable when a parent dialog already supplies the paper and outline. */
|
|
5
|
+
surface?: boolean;
|
|
6
|
+
};
|
|
4
7
|
export type CommandInputProps = Omit<ComponentPropsWithoutRef<typeof Primitive.Input>, 'asChild'>;
|
|
5
8
|
export type CommandListProps = Omit<ComponentPropsWithoutRef<typeof Primitive.List>, 'asChild'>;
|
|
6
9
|
export interface CommandItemProps extends Omit<ComponentPropsWithoutRef<typeof Primitive.Item>, 'asChild'> {
|
|
@@ -12,7 +15,26 @@ export type CommandEmptyProps = Omit<ComponentPropsWithoutRef<typeof Primitive.E
|
|
|
12
15
|
export type CommandSeparatorProps = Omit<ComponentPropsWithoutRef<typeof Primitive.Separator>, 'asChild' | 'children'>;
|
|
13
16
|
export type CommandShortcutProps = HTMLAttributes<HTMLElement>;
|
|
14
17
|
export declare const Command: {
|
|
15
|
-
Root: import("react").ForwardRefExoticComponent<
|
|
18
|
+
Root: import("react").ForwardRefExoticComponent<Omit<Omit<{
|
|
19
|
+
children?: React.ReactNode;
|
|
20
|
+
} & Pick<Pick<import("react").DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof HTMLAttributes<HTMLDivElement>> & {
|
|
21
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
22
|
+
} & {
|
|
23
|
+
asChild?: boolean;
|
|
24
|
+
}, "key" | keyof HTMLAttributes<HTMLDivElement> | "asChild"> & {
|
|
25
|
+
label?: string;
|
|
26
|
+
shouldFilter?: boolean;
|
|
27
|
+
filter?: (value: string, search: string, keywords?: string[]) => number;
|
|
28
|
+
defaultValue?: string;
|
|
29
|
+
value?: string;
|
|
30
|
+
onValueChange?: (value: string) => void;
|
|
31
|
+
loop?: boolean;
|
|
32
|
+
disablePointerSelection?: boolean;
|
|
33
|
+
vimBindings?: boolean;
|
|
34
|
+
} & import("react").RefAttributes<HTMLDivElement>, "ref">, "asChild"> & {
|
|
35
|
+
/** Disable when a parent dialog already supplies the paper and outline. */
|
|
36
|
+
surface?: boolean;
|
|
37
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
16
38
|
Input: import("react").ForwardRefExoticComponent<CommandInputProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
17
39
|
List: import("react").ForwardRefExoticComponent<CommandListProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
18
40
|
Group: import("react").ForwardRefExoticComponent<CommandGroupProps & import("react").RefAttributes<HTMLDivElement>>;
|
package/dist/command/index.js
CHANGED
|
@@ -6,14 +6,14 @@ import { PencilText } from '../PencilText.js';
|
|
|
6
6
|
import { PencilLine } from '../PencilLine.js';
|
|
7
7
|
function classes(base, extra) { return [base, extra].filter(Boolean).join(' '); }
|
|
8
8
|
function copy(value) { return typeof value === 'string' ? _jsx(PencilText, { children: value }) : value; }
|
|
9
|
-
const Root = forwardRef(function Root({ className, children, loop = true, onKeyDown, onCompositionStartCapture, onCompositionEndCapture, ...props }, ref) {
|
|
9
|
+
const Root = forwardRef(function Root({ className, children, loop = true, surface = true, onKeyDown, onCompositionStartCapture, onCompositionEndCapture, ...props }, ref) {
|
|
10
10
|
const composing = useRef(false);
|
|
11
11
|
return _jsx(Primitive, { ...props, ref: ref, loop: loop, className: classes('inkra-command', className), onCompositionStartCapture: event => { composing.current = true; onCompositionStartCapture?.(event); }, onCompositionEndCapture: event => { composing.current = false; onCompositionEndCapture?.(event); }, onKeyDown: event => {
|
|
12
12
|
// Capture composition state as well as native flags before cmdk handles Enter.
|
|
13
13
|
if (event.key === 'Enter' && (composing.current || event.nativeEvent.isComposing || event.keyCode === 229))
|
|
14
14
|
event.preventDefault();
|
|
15
15
|
onKeyDown?.(event);
|
|
16
|
-
}, children: _jsx(PencilSurface, { variant: "paper", radius: 8, className: "inkra-command__paper", children: children }) });
|
|
16
|
+
}, children: surface ? _jsx(PencilSurface, { variant: "paper", radius: 8, className: "inkra-command__paper", children: children }) : children });
|
|
17
17
|
});
|
|
18
18
|
const Input = forwardRef(function Input({ className, ...props }, ref) {
|
|
19
19
|
return _jsxs("div", { className: "inkra-command__input-wrap", children: [_jsx(Primitive.Input, { ...props, ref: ref, className: classes('inkra-command__input', className) }), _jsx(PencilLine, { className: "inkra-command__input-line" })] });
|
|
@@ -31,7 +31,7 @@ export interface ContextMenuTriggerProps extends Omit<HTMLAttributes<HTMLElement
|
|
|
31
31
|
}
|
|
32
32
|
export declare const ContextMenuTrigger: import("react").ForwardRefExoticComponent<ContextMenuTriggerProps & import("react").RefAttributes<HTMLElement>>;
|
|
33
33
|
export type ContextMenuPortalProps = ComponentPropsWithoutRef<typeof DropdownMenu.Portal>;
|
|
34
|
-
export declare const ContextMenuPortal: ({ children, ...props }: import("../dropdown-menu/index.js").DropdownMenuPortalProps) =>
|
|
34
|
+
export declare const ContextMenuPortal: ({ children, ...props }: import("../dropdown-menu/index.js").DropdownMenuPortalProps) => ReactNode;
|
|
35
35
|
export type ContextMenuContentProps = DropdownMenuContentProps;
|
|
36
36
|
export declare const ContextMenuContent: import("react").ForwardRefExoticComponent<DropdownMenuContentProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
37
37
|
export type ContextMenuItemProps = ComponentPropsWithoutRef<typeof DropdownMenu.Item>;
|
|
@@ -61,7 +61,7 @@ export declare const ContextMenuSubContent: import("react").ForwardRefExoticComp
|
|
|
61
61
|
export declare const ContextMenu: Readonly<{
|
|
62
62
|
Root: typeof ContextMenuRoot;
|
|
63
63
|
Trigger: import("react").ForwardRefExoticComponent<ContextMenuTriggerProps & import("react").RefAttributes<HTMLElement>>;
|
|
64
|
-
Portal: ({ children, ...props }: import("../dropdown-menu/index.js").DropdownMenuPortalProps) =>
|
|
64
|
+
Portal: ({ children, ...props }: import("../dropdown-menu/index.js").DropdownMenuPortalProps) => ReactNode;
|
|
65
65
|
Content: import("react").ForwardRefExoticComponent<DropdownMenuContentProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
66
66
|
Item: import("react").ForwardRefExoticComponent<import("../dropdown-menu/index.js").DropdownMenuItemProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
67
67
|
CheckboxItem: import("react").ForwardRefExoticComponent<import("../dropdown-menu/index.js").DropdownMenuCheckboxItemProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -5,7 +5,7 @@ import { DropdownMenu } from '../dropdown-menu/index.js';
|
|
|
5
5
|
import { PencilIcon } from '../PencilIcon.js';
|
|
6
6
|
import { PencilSurface } from '../PencilSurface.js';
|
|
7
7
|
import { PencilText } from '../PencilText.js';
|
|
8
|
-
import {
|
|
8
|
+
import { usePortalThemeProps, PortalThemeProvider, usePortalTriggerRef, } from '../overlay/themeBridge.js';
|
|
9
9
|
const DEFAULT_EXCLUDE = '[data-context-menu-native]';
|
|
10
10
|
const DEFAULT_LONG_PRESS_DELAY = 600;
|
|
11
11
|
const DEFAULT_LONG_PRESS_TOLERANCE = 10;
|
|
@@ -220,7 +220,8 @@ export const ContextMenuSubTrigger = forwardRef(function ContextMenuSubTrigger({
|
|
|
220
220
|
});
|
|
221
221
|
export const ContextMenuSubContent = forwardRef(function ContextMenuSubContent({ children, className, collisionPadding = 8, seed, sideOffset = 4, ...props }, ref) {
|
|
222
222
|
const id = useId();
|
|
223
|
-
|
|
223
|
+
props = usePortalThemeProps(props);
|
|
224
|
+
return (_jsx(Primitive.Portal, { children: _jsx(Primitive.SubContent, { ...props, className: classes('inkra-menu', 'inkra-context-menu__sub-content', className), collisionPadding: collisionPadding, ref: ref, sideOffset: sideOffset, children: _jsx(PencilSurface, { className: "inkra-menu__paper", radius: 8, seed: seed ?? `context-submenu-${id}`, variant: "paper", children: children }) }) }));
|
|
224
225
|
});
|
|
225
226
|
export const ContextMenu = Object.freeze({
|
|
226
227
|
Root: ContextMenuRoot,
|
package/dist/drawer/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare function DrawerRoot(props: DrawerRootProps): import("react").JSX.
|
|
|
8
8
|
export type DrawerTriggerProps = DialogPrimitive.DialogTriggerProps;
|
|
9
9
|
export declare const DrawerTrigger: import("react").ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
10
10
|
export type DrawerPortalProps = DialogPrimitive.DialogPortalProps;
|
|
11
|
-
export declare function DrawerPortal({ children, ...props }: DrawerPortalProps):
|
|
11
|
+
export declare function DrawerPortal({ children, ...props }: DrawerPortalProps): ReactNode;
|
|
12
12
|
export type DrawerBackdropProps = DialogPrimitive.DialogOverlayProps;
|
|
13
13
|
export declare const DrawerBackdrop: import("react").ForwardRefExoticComponent<DialogPrimitive.DialogOverlayProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
14
14
|
export interface DrawerContentProps extends DialogPrimitive.DialogContentProps {
|
package/dist/drawer/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { PencilLine } from '../PencilLine.js';
|
|
|
8
8
|
import { PencilSurface } from '../PencilSurface.js';
|
|
9
9
|
import { PencilText } from '../PencilText.js';
|
|
10
10
|
import { Tooltip } from '../tooltip/Tooltip.js';
|
|
11
|
-
import {
|
|
11
|
+
import { mapPortalChildren, PortalThemeProvider, usePortalThemeProps, usePortalTriggerRef, } from '../overlay/themeBridge.js';
|
|
12
12
|
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
13
13
|
const closePaths = closeIcon.node.map(([, attributes]) => ({ d: attributes.d }));
|
|
14
14
|
function drawerSize(size) {
|
|
@@ -29,16 +29,18 @@ export const DrawerTrigger = forwardRef(function DrawerTrigger(props, forwardedR
|
|
|
29
29
|
return _jsx(DialogPrimitive.Trigger, { ...props, ref: usePortalTriggerRef(forwardedRef) });
|
|
30
30
|
});
|
|
31
31
|
export function DrawerPortal({ children, ...props }) {
|
|
32
|
-
return _jsx(DialogPrimitive.Portal, { ...props, children:
|
|
32
|
+
return mapPortalChildren(children, child => _jsx(DialogPrimitive.Portal, { ...props, children: child }));
|
|
33
33
|
}
|
|
34
34
|
export const DrawerBackdrop = forwardRef(function DrawerBackdrop({ className, ...props }, ref) {
|
|
35
|
+
props = usePortalThemeProps(props);
|
|
35
36
|
return _jsx(DialogPrimitive.Overlay, { ...props, className: classes('inkra-drawer__backdrop', className), ref: ref });
|
|
36
37
|
});
|
|
37
38
|
export const DrawerContent = forwardRef(function DrawerContent({ children, className, direction = 'right', seed, size = 'md', style, ...props }, ref) {
|
|
38
39
|
const id = useId();
|
|
39
|
-
const
|
|
40
|
+
const themedProps = usePortalThemeProps({ ...props, style });
|
|
41
|
+
const mergedStyle = { ...themedProps.style, '--inkra-drawer-size': drawerSize(size) };
|
|
40
42
|
const edgeOrientation = direction === 'left' || direction === 'right' ? 'vertical' : 'horizontal';
|
|
41
|
-
return (_jsx(DialogPrimitive.Content, { ...
|
|
43
|
+
return (_jsx(DialogPrimitive.Content, { ...themedProps, className: classes('inkra-drawer__content', className), "data-direction": direction, ref: ref, style: mergedStyle, children: _jsxs(PencilSurface, { className: "inkra-drawer__surface", radius: 0, seed: seed ?? `inkra-drawer-${id}`, variant: "full", children: [_jsx(PencilLine, { className: "inkra-drawer__edge", orientation: edgeOrientation, seed: `drawer-edge-${id}` }), _jsx("div", { className: "inkra-drawer__layout", children: children })] }) }));
|
|
42
44
|
});
|
|
43
45
|
export const DrawerTitle = forwardRef(function DrawerTitle({ children, className, seed, ...props }, ref) {
|
|
44
46
|
const id = useId();
|
|
@@ -4,7 +4,7 @@ export type DropdownMenuProps = Primitive.DropdownMenuProps;
|
|
|
4
4
|
declare function Root(props: DropdownMenuProps): import("react").JSX.Element;
|
|
5
5
|
export type DropdownMenuTriggerProps = Primitive.DropdownMenuTriggerProps;
|
|
6
6
|
export type DropdownMenuPortalProps = Primitive.DropdownMenuPortalProps;
|
|
7
|
-
declare function Portal({ children, ...props }: DropdownMenuPortalProps):
|
|
7
|
+
declare function Portal({ children, ...props }: DropdownMenuPortalProps): ReactNode;
|
|
8
8
|
export interface DropdownMenuContentProps extends Omit<Primitive.DropdownMenuContentProps, 'asChild'> {
|
|
9
9
|
seed?: string | number;
|
|
10
10
|
}
|
|
@@ -5,16 +5,17 @@ import { PencilSurface } from '../PencilSurface.js';
|
|
|
5
5
|
import { PencilText } from '../PencilText.js';
|
|
6
6
|
import { PencilIcon } from '../PencilIcon.js';
|
|
7
7
|
import { PencilLine } from '../PencilLine.js';
|
|
8
|
-
import {
|
|
8
|
+
import { mapPortalChildren, PortalThemeProvider, usePortalThemeProps, usePortalTriggerRef } from '../overlay/themeBridge.js';
|
|
9
9
|
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
10
10
|
const copy = (children) => typeof children === 'string' ? _jsx(PencilText, { children: children }) : children;
|
|
11
11
|
function Root(props) { return _jsx(PortalThemeProvider, { children: _jsx(Primitive.Root, { ...props }) }); }
|
|
12
12
|
const Trigger = forwardRef(function Trigger(props, ref) {
|
|
13
13
|
return _jsx(Primitive.Trigger, { ...props, ref: usePortalTriggerRef(ref) });
|
|
14
14
|
});
|
|
15
|
-
function Portal({ children, ...props }) { return _jsx(Primitive.Portal, { ...props, children:
|
|
15
|
+
function Portal({ children, ...props }) { return mapPortalChildren(children, child => _jsx(Primitive.Portal, { ...props, children: child })); }
|
|
16
16
|
const Content = forwardRef(function Content({ className, children, seed, sideOffset = 6, collisionPadding = 8, ...props }, ref) {
|
|
17
17
|
const id = useId();
|
|
18
|
+
props = usePortalThemeProps(props);
|
|
18
19
|
return _jsx(Primitive.Content, { ...props, ref: ref, sideOffset: sideOffset, collisionPadding: collisionPadding, className: classes('inkra-menu', className), children: _jsx(PencilSurface, { variant: "paper", radius: 8, seed: seed ?? `menu-${id}`, className: "inkra-menu__paper", children: children }) });
|
|
19
20
|
});
|
|
20
21
|
function ItemBody({ children, icon }) {
|
|
@@ -213,6 +213,8 @@ export function EditablePencilText({ controlRef, defaultValue, multiline = false
|
|
|
213
213
|
let glyphs = new BoundedCache(128, 4 * 1024 * 1024);
|
|
214
214
|
let disposed = false;
|
|
215
215
|
let lastAppearance = '';
|
|
216
|
+
const numericControl = control instanceof HTMLInputElement && control.type === 'number';
|
|
217
|
+
let nativeNumberEditing = false;
|
|
216
218
|
const appearanceKey = () => {
|
|
217
219
|
const style = getComputedStyle(control);
|
|
218
220
|
return JSON.stringify([
|
|
@@ -230,6 +232,12 @@ export function EditablePencilText({ controlRef, defaultValue, multiline = false
|
|
|
230
232
|
const paint = () => {
|
|
231
233
|
if (disposed)
|
|
232
234
|
return;
|
|
235
|
+
// Number inputs expose a sanitized value, not incomplete drafts such as "-" or "1.".
|
|
236
|
+
if (numericControl && (nativeNumberEditing || control.validity.badInput || composingRef.current)) {
|
|
237
|
+
root?.removeAttribute('data-pencil-editable-ready');
|
|
238
|
+
lastAppearance = '';
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
233
241
|
const key = appearanceKey();
|
|
234
242
|
if (key === lastAppearance && root?.hasAttribute('data-pencil-editable-ready'))
|
|
235
243
|
return;
|
|
@@ -249,7 +257,25 @@ export function EditablePencilText({ controlRef, defaultValue, multiline = false
|
|
|
249
257
|
}
|
|
250
258
|
};
|
|
251
259
|
scheduleRef.current = paint;
|
|
260
|
+
const beforeInput = (event) => {
|
|
261
|
+
if (!numericControl || event.defaultPrevented)
|
|
262
|
+
return;
|
|
263
|
+
nativeNumberEditing = true;
|
|
264
|
+
root?.setAttribute('data-pencil-number-editing', 'true');
|
|
265
|
+
paint();
|
|
266
|
+
};
|
|
267
|
+
const finishNumberEditing = () => {
|
|
268
|
+
if (!numericControl)
|
|
269
|
+
return;
|
|
270
|
+
nativeNumberEditing = false;
|
|
271
|
+
root?.removeAttribute('data-pencil-number-editing');
|
|
272
|
+
paint();
|
|
273
|
+
};
|
|
252
274
|
const startComposition = () => {
|
|
275
|
+
if (numericControl) {
|
|
276
|
+
nativeNumberEditing = true;
|
|
277
|
+
root?.setAttribute('data-pencil-number-editing', 'true');
|
|
278
|
+
}
|
|
253
279
|
composingRef.current = {
|
|
254
280
|
value: control.value,
|
|
255
281
|
start: control.selectionStart ?? control.value.length,
|
|
@@ -273,6 +299,8 @@ export function EditablePencilText({ controlRef, defaultValue, multiline = false
|
|
|
273
299
|
return;
|
|
274
300
|
composingRef.current = null;
|
|
275
301
|
root?.removeAttribute('data-composing');
|
|
302
|
+
nativeNumberEditing = false;
|
|
303
|
+
root?.removeAttribute('data-pencil-number-editing');
|
|
276
304
|
refreshFonts();
|
|
277
305
|
});
|
|
278
306
|
const form = control.form;
|
|
@@ -284,6 +312,8 @@ export function EditablePencilText({ controlRef, defaultValue, multiline = false
|
|
|
284
312
|
}
|
|
285
313
|
const colorScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
|
286
314
|
colorScheme.addEventListener('change', paint);
|
|
315
|
+
control.addEventListener('beforeinput', beforeInput);
|
|
316
|
+
control.addEventListener('blur', finishNumberEditing);
|
|
287
317
|
control.addEventListener('input', paint);
|
|
288
318
|
control.addEventListener('scroll', paint, { passive: true });
|
|
289
319
|
control.addEventListener('compositionstart', startComposition);
|
|
@@ -301,6 +331,8 @@ export function EditablePencilText({ controlRef, defaultValue, multiline = false
|
|
|
301
331
|
resize?.disconnect();
|
|
302
332
|
appearance.disconnect();
|
|
303
333
|
colorScheme.removeEventListener('change', paint);
|
|
334
|
+
control.removeEventListener('beforeinput', beforeInput);
|
|
335
|
+
control.removeEventListener('blur', finishNumberEditing);
|
|
304
336
|
control.removeEventListener('input', paint);
|
|
305
337
|
control.removeEventListener('scroll', paint);
|
|
306
338
|
control.removeEventListener('compositionstart', startComposition);
|
|
@@ -310,9 +342,11 @@ export function EditablePencilText({ controlRef, defaultValue, multiline = false
|
|
|
310
342
|
document.fonts?.removeEventListener('loadingerror', refreshFonts);
|
|
311
343
|
root?.removeAttribute('data-pencil-editable-ready');
|
|
312
344
|
root?.removeAttribute('data-composing');
|
|
345
|
+
root?.removeAttribute('data-pencil-number-editing');
|
|
313
346
|
composingRef.current = null;
|
|
314
347
|
glyphs = new BoundedCache(0, 0);
|
|
315
348
|
buffer.width = buffer.height = 0;
|
|
349
|
+
canvas.width = canvas.height = 0;
|
|
316
350
|
scheduleRef.current = () => { };
|
|
317
351
|
};
|
|
318
352
|
}, [controlRef, multiline, seed]);
|
package/dist/form/Input.js
CHANGED
|
@@ -7,7 +7,7 @@ import { PencilText } from '../PencilText.js';
|
|
|
7
7
|
import { InputAction } from './InputAction.js';
|
|
8
8
|
import { useResolvedControlProps } from './controlProps.js';
|
|
9
9
|
import { EditablePencilText } from './EditablePencilText.js';
|
|
10
|
-
const editablePencilInputTypes = new Set(['text', 'search', 'email', 'url', 'tel']);
|
|
10
|
+
const editablePencilInputTypes = new Set(['text', 'search', 'email', 'url', 'tel', 'number']);
|
|
11
11
|
const clearableInputTypes = new Set(['text', 'search', 'email', 'url', 'tel', 'password', 'number']);
|
|
12
12
|
// Lucide X / LoaderCircle ISC geometry, rendered by the shared pencil engine.
|
|
13
13
|
const clearPaths = [{ d: 'M18 6 6 18' }, { d: 'm6 6 12 12' }];
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { InputProps } from '../form/Input.js';
|
|
2
|
+
import { type InputNumberStepModifier } from './model.js';
|
|
3
|
+
export type { InputNumberStepModifier } from './model.js';
|
|
2
4
|
export interface InputNumberValueChangeDetails {
|
|
3
5
|
reason: 'input' | 'increment' | 'decrement';
|
|
4
6
|
}
|
|
@@ -9,6 +11,10 @@ export interface InputNumberProps extends Omit<InputProps, 'type' | 'value' | 'd
|
|
|
9
11
|
min?: number;
|
|
10
12
|
max?: number;
|
|
11
13
|
step?: number | 'any';
|
|
14
|
+
stepModifiers?: readonly InputNumberStepModifier[];
|
|
15
|
+
pressAndHold?: boolean;
|
|
16
|
+
repeatDelay?: number;
|
|
17
|
+
repeatInterval?: number;
|
|
12
18
|
controls?: boolean;
|
|
13
19
|
incrementButtonLabel?: string;
|
|
14
20
|
decrementButtonLabel?: string;
|