@inkra/react 0.1.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 +186 -1
- package/dist/PencilIcon.js +14 -16
- package/dist/PencilLine.js +18 -12
- package/dist/PencilText.js +192 -59
- package/dist/alert-dialog/index.d.ts +64 -0
- package/dist/alert-dialog/index.js +111 -0
- package/dist/audio-player/index.d.ts +60 -0
- package/dist/audio-player/index.js +101 -0
- package/dist/carousel/index.d.ts +51 -0
- package/dist/carousel/index.js +290 -0
- package/dist/choice-grid/index.d.ts +38 -0
- package/dist/choice-grid/index.js +85 -0
- package/dist/color-picker/color.d.ts +15 -0
- package/dist/color-picker/color.js +55 -0
- package/dist/color-picker/index.d.ts +31 -0
- package/dist/color-picker/index.js +69 -0
- package/dist/command/index.d.ts +45 -0
- package/dist/command/index.js +39 -0
- package/dist/context-menu/index.d.ts +76 -0
- package/dist/context-menu/index.js +241 -0
- package/dist/data-table/index.d.ts +47 -0
- package/dist/data-table/index.js +91 -0
- package/dist/date-picker/index.d.ts +50 -0
- package/dist/date-picker/index.js +180 -0
- package/dist/display/ProgressRing.d.ts +6 -0
- package/dist/display/ProgressRing.js +146 -0
- package/dist/display/index.d.ts +27 -0
- package/dist/display/index.js +18 -2
- package/dist/dockable-panel/index.d.ts +41 -0
- package/dist/dockable-panel/index.js +253 -0
- package/dist/dockable-panel/model.d.ts +21 -0
- package/dist/dockable-panel/model.js +61 -0
- package/dist/drawer/index.d.ts +63 -0
- package/dist/drawer/index.js +88 -0
- package/dist/dropdown-menu/index.d.ts +1 -1
- package/dist/dropdown-menu/index.js +3 -2
- package/dist/editable/index.d.ts +53 -0
- package/dist/editable/index.js +162 -0
- package/dist/empty/index.d.ts +21 -0
- package/dist/empty/index.js +23 -0
- package/dist/flip/index.d.ts +49 -0
- package/dist/flip/index.js +138 -0
- package/dist/form/EditablePencilText.js +188 -143
- package/dist/form/Input.js +1 -1
- package/dist/form/Textarea.d.ts +12 -0
- package/dist/form/Textarea.js +83 -4
- package/dist/form/index.d.ts +1 -1
- package/dist/heatmap/index.d.ts +59 -0
- package/dist/heatmap/index.js +248 -0
- package/dist/hotkey/index.d.ts +37 -0
- package/dist/hotkey/index.js +130 -0
- package/dist/hotkey/model.d.ts +27 -0
- package/dist/hotkey/model.js +97 -0
- package/dist/hover-card/index.d.ts +33 -0
- package/dist/hover-card/index.js +141 -0
- package/dist/image-cropper/index.d.ts +82 -0
- package/dist/image-cropper/index.js +261 -0
- package/dist/image-cropper/model.d.ts +42 -0
- package/dist/image-cropper/model.js +94 -0
- package/dist/image-viewer/index.d.ts +79 -0
- package/dist/image-viewer/index.js +220 -0
- package/dist/image-viewer/model.d.ts +9 -0
- package/dist/image-viewer/model.js +18 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +47 -0
- 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/internal/cache.d.ts +1 -1
- package/dist/internal/cache.js +1 -1
- package/dist/internal/renderTokens.d.ts +10 -0
- package/dist/internal/renderTokens.js +13 -0
- package/dist/internal/surfaceRenderer.d.ts +14 -6
- package/dist/internal/surfaceRenderer.js +15 -12
- package/dist/internal/textRenderer.d.ts +1 -0
- package/dist/internal/textRenderer.js +33 -7
- package/dist/internal/usePencilSurface.js +16 -8
- package/dist/internal/useSelectionDrawing.js +15 -11
- package/dist/journey-map/MapScale.js +3 -1
- package/dist/journey-map/index.js +3 -1
- package/dist/keypad/index.d.ts +23 -0
- package/dist/keypad/index.js +63 -0
- package/dist/keypad/model.d.ts +20 -0
- package/dist/keypad/model.js +33 -0
- package/dist/layout/index.d.ts +63 -0
- package/dist/layout/index.js +62 -0
- package/dist/log/index.d.ts +45 -0
- package/dist/log/index.js +159 -0
- package/dist/log/model.d.ts +16 -0
- package/dist/log/model.js +13 -0
- package/dist/node-graph/index.d.ts +123 -0
- package/dist/node-graph/index.js +304 -0
- package/dist/number-ticker/index.d.ts +31 -0
- package/dist/number-ticker/index.js +135 -0
- package/dist/number-ticker/model.d.ts +41 -0
- package/dist/number-ticker/model.js +163 -0
- package/dist/number-ticker/precision.d.ts +7 -0
- package/dist/number-ticker/precision.js +134 -0
- package/dist/overflow-list/index.d.ts +39 -0
- package/dist/overflow-list/index.js +230 -0
- package/dist/overflow-list/layout.d.ts +19 -0
- package/dist/overflow-list/layout.js +44 -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/pagination/index.d.ts +23 -0
- package/dist/pagination/index.js +41 -0
- package/dist/pagination/model.d.ts +4 -0
- package/dist/pagination/model.js +42 -0
- package/dist/pan-zoom/index.d.ts +71 -0
- package/dist/pan-zoom/index.js +175 -0
- package/dist/radar/index.d.ts +56 -0
- package/dist/radar/index.js +220 -0
- package/dist/range-slider/index.d.ts +16 -0
- package/dist/range-slider/index.js +22 -0
- package/dist/rating/index.d.ts +28 -0
- package/dist/rating/index.js +127 -0
- package/dist/resizable/index.d.ts +32 -0
- package/dist/resizable/index.js +50 -0
- package/dist/scroll-area/index.d.ts +36 -0
- package/dist/scroll-area/index.js +44 -0
- package/dist/segmented-progress/SegmentedProgress.d.ts +17 -0
- package/dist/segmented-progress/SegmentedProgress.js +42 -0
- package/dist/slider/index.js +1 -1
- package/dist/slot/index.d.ts +24 -0
- package/dist/slot/index.js +29 -0
- package/dist/sortable/index.d.ts +50 -0
- package/dist/sortable/index.js +283 -0
- package/dist/sortable/model.d.ts +30 -0
- package/dist/sortable/model.js +64 -0
- package/dist/sparkline/index.d.ts +19 -0
- package/dist/sparkline/index.js +240 -0
- package/dist/sparkline/model.d.ts +16 -0
- package/dist/sparkline/model.js +28 -0
- package/dist/steps/index.d.ts +16 -0
- package/dist/steps/index.js +37 -0
- package/dist/styles.css +4957 -269
- package/dist/tag-input/index.d.ts +69 -0
- package/dist/tag-input/index.js +325 -0
- package/dist/tag-input/model.d.ts +14 -0
- package/dist/tag-input/model.js +38 -0
- package/dist/time-picker/index.d.ts +15 -0
- package/dist/time-picker/index.js +168 -0
- package/dist/timeline/index.d.ts +14 -0
- package/dist/timeline/index.js +16 -0
- package/dist/toast/index.d.ts +27 -0
- package/dist/toast/index.js +36 -0
- package/dist/toggle-group/index.d.ts +17 -0
- package/dist/toggle-group/index.js +26 -0
- package/dist/tokens.css +10 -9
- package/dist/tooltip/Tooltip.d.ts +1 -1
- package/dist/tooltip/Tooltip.js +3 -2
- package/dist/transfer/index.d.ts +64 -0
- package/dist/transfer/index.js +174 -0
- package/dist/transfer/model.d.ts +12 -0
- package/dist/transfer/model.js +33 -0
- package/dist/tree/index.d.ts +39 -0
- package/dist/tree/index.js +36 -0
- package/dist/tree-select/index.d.ts +59 -0
- package/dist/tree-select/index.js +142 -0
- package/dist/tree-select/model.d.ts +31 -0
- package/dist/tree-select/model.js +135 -0
- package/dist/typewriter/index.d.ts +21 -0
- package/dist/typewriter/index.js +101 -0
- package/dist/typewriter/model.d.ts +7 -0
- package/dist/typewriter/model.js +45 -0
- package/dist/upload/index.d.ts +59 -0
- package/dist/upload/index.js +230 -0
- package/dist/virtual-list/index.d.ts +44 -0
- package/dist/virtual-list/index.js +129 -0
- package/dist/virtual-list/model.d.ts +7 -0
- package/dist/virtual-list/model.js +27 -0
- package/package.json +23 -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.
|
|
@@ -150,12 +162,31 @@ outside interaction, modal focus trapping and focus return.
|
|
|
150
162
|
<Skeleton style={{ width: 200, height: 20 }} />
|
|
151
163
|
<Progress label="Uploading" value={60} />
|
|
152
164
|
<Progress aria-label="Loading" value={null} />
|
|
165
|
+
<Progress shape="circular" value={72} diameter={128} thickness={6} aria-label="Download">
|
|
166
|
+
{({ percent }) => `${Math.round(percent ?? 0)}%`}
|
|
167
|
+
</Progress>
|
|
168
|
+
<Progress shape="circular" value={3} max={5} contentPosition="end" label="Files">
|
|
169
|
+
<span>3 / 5 files</span>
|
|
170
|
+
</Progress>
|
|
153
171
|
```
|
|
154
172
|
|
|
155
173
|
`Badge` variants are `neutral`, `accent`, `success`, `warning`, `danger` and `info`. `Separator` has horizontal/vertical orientation and a decorative opt-out. `Skeleton` is a static, aria-hidden placeholder; mark its loading container `aria-busy`. `Progress` clamps numeric values to `0..max` (default 100); `null` is indeterminate without a fabricated percentage. Always provide a progress label.
|
|
156
174
|
|
|
157
175
|
`Badge.size` accepts `sm | md | lg` with optional `startIcon` and `endIcon`. `Separator.weight` clamps to 0.3–2 (default 0.9). `Skeleton.radius` uses the existing 0–8px pencil corner contract. `Progress.size` selects a 12/16/24px track (`sm/md/lg`); `dir`, `aria-valuetext`, refs and native DOM attributes remain available. Tooltip exposes the underlying delay, alignment, collision and hoverable-content controls alongside `Content.surfaceRadius`.
|
|
158
176
|
|
|
177
|
+
Circular Progress uses a grainy pencil arc with naturally tapered ends and an
|
|
178
|
+
empty gap for the remaining progress.
|
|
179
|
+
`size` selects a 64/96/128px diameter; `diameter` overrides it (32-512px), and
|
|
180
|
+
`thickness` sets the base stroke width (1-diameter/8px, affected by global stroke
|
|
181
|
+
settings). `children` accepts non-interactive icons/text or a render function
|
|
182
|
+
receiving normalized `{ value, max, percent }`; unknown value/percent are null.
|
|
183
|
+
`contentPosition` supports `center`, `top`, `bottom`, `start`, and `end`; logical
|
|
184
|
+
sides follow RTL. Circular defaults to center, linear to end (including explicit
|
|
185
|
+
center). Keep center content short; longer descriptions belong outside the ring.
|
|
186
|
+
Always supply a label or ARIA name, even for icon content. Progress updates reveal
|
|
187
|
+
the existing texture; only unknown progress rotates, respecting reduced motion.
|
|
188
|
+
Canvas failures, forced colors and printing retain an SVG progress fallback.
|
|
189
|
+
|
|
159
190
|
## Menus And Content
|
|
160
191
|
|
|
161
192
|
`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.
|
|
@@ -176,6 +207,133 @@ Content layout options preserve existing defaults:
|
|
|
176
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).
|
|
177
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.
|
|
178
209
|
|
|
210
|
+
## Additional Components
|
|
211
|
+
|
|
212
|
+
These exports extend the original core component set. The documentation playground includes
|
|
213
|
+
working examples, live property tabs and per-component API/accessibility notes.
|
|
214
|
+
|
|
215
|
+
| Component | Contract |
|
|
216
|
+
| --- | --- |
|
|
217
|
+
| Toast | `Provider`, `useToastManager`, `createToastManager`; add/update/close/promise notifications, named actions and timer pause managed by Base UI |
|
|
218
|
+
| AlertDialog | Always-modal confirmation; `Root`, `Trigger`, `Portal`, `Backdrop`, `Content`, `Header`, `Body`, `Footer`, `Title`, `Description`, `Cancel`, `Action`; pending blocks user dismissal, async actions use `closeOnAction={false}` |
|
|
219
|
+
| Drawer | Dialog parts plus section layout, four `Content.direction` values and token/custom `size`; focus trap, Escape and return focus, no swipe gesture API |
|
|
220
|
+
| DatePicker | Calendar/Popover composition; single/range local dates, controlled/default values, clear, form fields and localized labels; no UTC conversion |
|
|
221
|
+
| TimePicker | Native time input with clear, disabled/readOnly, min/max/step and optional seconds; browser/OS controls the native presentation |
|
|
222
|
+
| Pagination | Page count/current page, boundary actions and ellipses; buttons change local state rather than pretending to navigate URLs |
|
|
223
|
+
| Empty | Optional `Root`, `Icon`, `Title`, `Description`, `Actions`; no mandatory card or live-region role |
|
|
224
|
+
| ToggleGroup | `Root` and `Item`; array values for single/multiple toggles, roving focus and `aria-pressed`, not tabs |
|
|
225
|
+
| Command | cmdk-backed search, grouped commands, empty/disabled states and optional modal composition |
|
|
226
|
+
| Upload | File selection/drop, type/size/count rejection, removal, progress, cancel and retry; application transport receives `AbortSignal` and `reportProgress` |
|
|
227
|
+
| DataTable | Typed columns, required stable `getRowId`, sorting, filtering, pagination, selection, empty/loading state; native table semantics |
|
|
228
|
+
| Tree | `Root`, `Item`, `ItemContent`, `ItemTitle`, `ItemDescription`; stable keys, expansion and selection via React Aria; no drag/drop |
|
|
229
|
+
| Steps | Ordered `items`, `current`, orientation and optional `onStepChange`; status and disabled steps |
|
|
230
|
+
| Timeline | Ordered `items` with date/title/description/content, semantic `dateTime` and horizontal/vertical orientation |
|
|
231
|
+
|
|
232
|
+
## Utility Components (Unreleased)
|
|
233
|
+
|
|
234
|
+
`Slot` is a fixed square visual container for arbitrary icons or content. Static
|
|
235
|
+
slots render a `div`; `interactive` slots render one native button with
|
|
236
|
+
`aria-pressed` selection and native Enter/Space behavior. `empty` preserves
|
|
237
|
+
geometry, `count` reuses Badge, and `renderCount` keeps custom rendering at the
|
|
238
|
+
logical corner. Keep nested controls out of interactive slots. Slot does not
|
|
239
|
+
implement equipment rules, rarity, sorting or drag and drop.
|
|
240
|
+
|
|
241
|
+
`Hotkey` formats shortcut values for Mac or Windows. `HotkeyInput` records only
|
|
242
|
+
while its native input is focused, supports controlled/uncontrolled values,
|
|
243
|
+
clear, Escape cancellation, read-only/disabled states, IME safeguards and
|
|
244
|
+
caller-owned conflict validation. It does not register global shortcut listeners
|
|
245
|
+
or suppress browser shortcuts.
|
|
246
|
+
|
|
247
|
+
`NumberTicker` formats values with `Intl.NumberFormat`, optionally animates from
|
|
248
|
+
the currently displayed frame, and can show a temporary signed delta. Reduced
|
|
249
|
+
motion and SSR show deterministic final values. Intermediate frames are visual;
|
|
250
|
+
the polite announcement updates only at the final value. Use `getValueLabel`
|
|
251
|
+
when units or custom rendering need a complete accessible phrase.
|
|
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
|
+
|
|
324
|
+
`Log` renders caller-ordered records with stable ids, optional level filters and
|
|
325
|
+
pause/follow controls. It follows only append updates while the viewport remains
|
|
326
|
+
near the bottom. The named scroll region supports Home/End and intentionally is
|
|
327
|
+
not a live region, so a long stream is not repeatedly announced. Log does not
|
|
328
|
+
provide persistence, virtualization or transport.
|
|
329
|
+
|
|
330
|
+
Upload does not send files anywhere unless the application supplies `onUpload`.
|
|
331
|
+
Without a transport, files remain selected, not successfully uploaded. Client
|
|
332
|
+
validation is a convenience; the receiving server must validate files itself.
|
|
333
|
+
DataTable does not replace `Table` and does not promise virtualization, cell
|
|
334
|
+
editing or server-side transport. Tree is not a file-system permission boundary.
|
|
335
|
+
All examples use public sample data.
|
|
336
|
+
|
|
179
337
|
## Travel Components
|
|
180
338
|
|
|
181
339
|
`Calendar` wraps React DayPicker with default `appearance="itinerary"` day cards and optional `appearance="picker"`. It retains single/multiple/range selection, month control, disabled matchers, locale and keyboard navigation. Supply `selected` and `onSelect` for controlled selection. Events have independent `onEventSelect` handling; `displayRange` and `renderDayAccessory` customize the itinerary. Narrow itinerary grids retain seven columns and hide event text while preserving accessible names; picker targets remain at least 44px.
|
|
@@ -199,6 +357,33 @@ Content layout options preserve existing defaults:
|
|
|
199
357
|
<PencilLine orientation="vertical" seed="sidebar-divider" className="sidebar-divider" />
|
|
200
358
|
```
|
|
201
359
|
|
|
360
|
+
### Rendering tokens
|
|
361
|
+
|
|
362
|
+
`PencilText` reads `--inkra-letter-variation`, `--inkra-letter-breaks`,
|
|
363
|
+
`--inkra-letter-outline`, `--inkra-letter-fill`, and `--inkra-letter-grain` from
|
|
364
|
+
its computed style. Values are clamped to 0-1; missing or invalid values use the
|
|
365
|
+
default lettering preset (0.20, 0.50, 0.90, 0.90, 0.60 respectively). Apply these tokens to an ancestor to customize all
|
|
366
|
+
text within that scope without changing layout, selectable text, or labels.
|
|
367
|
+
|
|
368
|
+
`PencilLine` reads `--inkra-stroke-width` (0.3-3) and
|
|
369
|
+
`--inkra-stroke-amplitude` (0-4) when `weight` or `roughness` is omitted.
|
|
370
|
+
Explicit props take precedence. These tokens also scale surface outlines and icon
|
|
371
|
+
strokes relative to their original presets, including button/card/input borders.
|
|
372
|
+
The default values are 2 and 1.5. They do not change layout or text lettering.
|
|
373
|
+
|
|
374
|
+
Surface fills read `--inkra-wash-strength` (0-1, default 0.8),
|
|
375
|
+
`--inkra-wash-spacing` (1-6, default 2), `--inkra-wash-roughness` (0-6,
|
|
376
|
+
default 3), and `--inkra-wash-angle` (-85 to 85 degrees, default -45).
|
|
377
|
+
Strength scales each variant's original light/dark pigment intensity relative to
|
|
378
|
+
the original 0.48 reference. These settings affect button fills, selections
|
|
379
|
+
and swatches, not paper or lettering. Selection reveals follow the chosen angle.
|
|
380
|
+
|
|
381
|
+
Only self/ancestor appearance changes invalidate decoration, not unrelated theme
|
|
382
|
+
subtrees. Unchanged computed paint settings are reused, including when a dialog
|
|
383
|
+
changes body pointer events or scroll locks. Rendering settings are part of the
|
|
384
|
+
bounded texture cache keys. No page remount is needed. Forced-color, print, and
|
|
385
|
+
unavailable-canvas fallbacks remain intact.
|
|
386
|
+
|
|
202
387
|
## Font license
|
|
203
388
|
|
|
204
389
|
The package includes `Trip Map Hand`, a modified web subset of Yozai Light v0.868, under the SIL Open Font License 1.1. The font is not covered by Inkra's MIT software license. See `THIRD_PARTY_NOTICES.md` and `Yozai-OFL.txt` in the package.
|
package/dist/PencilIcon.js
CHANGED
|
@@ -4,6 +4,7 @@ import { BoundedCache, PENCIL_RENDERER_VERSION, canvasByteCost, canvasIsUsable,
|
|
|
4
4
|
import { observeCanvasRecovery } from './internal/recovery.js';
|
|
5
5
|
import { seedToNumber } from './internal/random.js';
|
|
6
6
|
import { pencilStroke } from './internal/stroke.js';
|
|
7
|
+
import { maxStrokeRoughness, pencilRenderDefaults, readRenderToken } from './internal/renderTokens.js';
|
|
7
8
|
const geometryCache = new BoundedCache(256, 180000);
|
|
8
9
|
const imageCache = new BoundedCache(128, 24 * 1024 * 1024);
|
|
9
10
|
function cachedPathParts(data) {
|
|
@@ -45,6 +46,7 @@ function drawFallbackPath(context, data, color, mode, weightScale = 1) {
|
|
|
45
46
|
function renderIcon(paths, options) {
|
|
46
47
|
const { seed, size, sourceSize, active, color, dpr } = options;
|
|
47
48
|
const weightScale = options.weightScale ?? 1;
|
|
49
|
+
const roughnessScale = options.roughnessScale ?? 1;
|
|
48
50
|
const canvas = document.createElement('canvas');
|
|
49
51
|
canvas.width = Math.round(size * dpr);
|
|
50
52
|
canvas.height = Math.round(size * dpr);
|
|
@@ -76,7 +78,7 @@ function renderIcon(paths, options) {
|
|
|
76
78
|
try {
|
|
77
79
|
const parts = cachedPathParts(path.d);
|
|
78
80
|
for (const points of parts) {
|
|
79
|
-
pencilStroke(context, points, color, (mode === 'scuff' ? 0.55 : 1.65) * weightScale, pathSeed, 0.3, mode === 'scuff' ? 1 : 3, false, {
|
|
81
|
+
pencilStroke(context, points, color, (mode === 'scuff' ? 0.55 : 1.65) * weightScale, pathSeed, 0.3 * roughnessScale, mode === 'scuff' ? 1 : 3, false, {
|
|
80
82
|
variation: 0.82,
|
|
81
83
|
breaks: 0.18,
|
|
82
84
|
grain: 0.68,
|
|
@@ -91,7 +93,7 @@ function renderIcon(paths, options) {
|
|
|
91
93
|
}
|
|
92
94
|
});
|
|
93
95
|
if (active) {
|
|
94
|
-
pencilStroke(context, [[sourceSize * 0.2, sourceSize - 2], [sourceSize * 0.5, sourceSize - 1.5], [sourceSize * 0.8, sourceSize - 2.2]], color, 1.1, seed + 977, 0.25, 3, false, { variation: 0.8, breaks: 0.25, grain: 0.7, gain: 2.8, step: 0.35 });
|
|
96
|
+
pencilStroke(context, [[sourceSize * 0.2, sourceSize - 2], [sourceSize * 0.5, sourceSize - 1.5], [sourceSize * 0.8, sourceSize - 2.2]], color, 1.1 * weightScale, seed + 977, 0.25 * roughnessScale, 3, false, { variation: 0.8, breaks: 0.25, grain: 0.7, gain: 2.8, step: 0.35 });
|
|
95
97
|
}
|
|
96
98
|
if (options.badge?.paths.length) {
|
|
97
99
|
const badge = options.badge;
|
|
@@ -104,7 +106,7 @@ function renderIcon(paths, options) {
|
|
|
104
106
|
const y = position.startsWith('top') ? 0 : 40 - extent;
|
|
105
107
|
const badgeImage = renderIcon(badge.paths, {
|
|
106
108
|
seed: seed + 1543, size: size * scale, sourceSize: badgeSourceSize, active: false, color, dpr,
|
|
107
|
-
weightScale:
|
|
109
|
+
weightScale: weightScale / scale, roughnessScale,
|
|
108
110
|
});
|
|
109
111
|
const mask = document.createElement('canvas');
|
|
110
112
|
mask.width = badgeImage.width;
|
|
@@ -135,6 +137,7 @@ function renderIcon(paths, options) {
|
|
|
135
137
|
}
|
|
136
138
|
export const PencilIcon = forwardRef(function PencilIcon({ active = false, badge, className = '', decorative = true, paths, seed, size = 40, sourceSize = 32, ...props }, forwardedRef) {
|
|
137
139
|
const canvasRef = useRef(null);
|
|
140
|
+
const lastPaintRef = useRef('');
|
|
138
141
|
useImperativeHandle(forwardedRef, () => canvasRef.current);
|
|
139
142
|
const geometryKey = useMemo(() => JSON.stringify(paths), [paths]);
|
|
140
143
|
const badgeKey = useMemo(() => badge ? JSON.stringify(badge) : '', [badge]);
|
|
@@ -144,7 +147,6 @@ export const PencilIcon = forwardRef(function PencilIcon({ active = false, badge
|
|
|
144
147
|
if (!canvas)
|
|
145
148
|
return undefined;
|
|
146
149
|
let disposed = false;
|
|
147
|
-
let lastPaint = '';
|
|
148
150
|
const paint = () => {
|
|
149
151
|
if (disposed)
|
|
150
152
|
return;
|
|
@@ -152,6 +154,8 @@ export const PencilIcon = forwardRef(function PencilIcon({ active = false, badge
|
|
|
152
154
|
const computed = getComputedStyle(canvas);
|
|
153
155
|
const color = computed.color;
|
|
154
156
|
const rtl = computed.direction === 'rtl';
|
|
157
|
+
const weightScale = readRenderToken(computed, '--inkra-stroke-width', pencilRenderDefaults.strokeWidth, 0.3, 3) / 1.2;
|
|
158
|
+
const roughnessScale = readRenderToken(computed, '--inkra-stroke-amplitude', pencilRenderDefaults.strokeRoughness, 0, maxStrokeRoughness) / 0.6;
|
|
155
159
|
const key = JSON.stringify([
|
|
156
160
|
PENCIL_RENDERER_VERSION,
|
|
157
161
|
geometryKey,
|
|
@@ -163,8 +167,9 @@ export const PencilIcon = forwardRef(function PencilIcon({ active = false, badge
|
|
|
163
167
|
active,
|
|
164
168
|
color,
|
|
165
169
|
dpr,
|
|
170
|
+
weightScale, roughnessScale,
|
|
166
171
|
]);
|
|
167
|
-
if (key ===
|
|
172
|
+
if (key === lastPaintRef.current && canvasIsUsable(canvas))
|
|
168
173
|
return;
|
|
169
174
|
let image = imageCache.get(key);
|
|
170
175
|
if (image && !canvasIsUsable(image)) {
|
|
@@ -172,7 +177,7 @@ export const PencilIcon = forwardRef(function PencilIcon({ active = false, badge
|
|
|
172
177
|
image = undefined;
|
|
173
178
|
}
|
|
174
179
|
if (!image) {
|
|
175
|
-
image = renderIcon(paths, { seed: resolvedSeed, size, sourceSize, active, color, dpr, badge, rtl });
|
|
180
|
+
image = renderIcon(paths, { seed: resolvedSeed, size, sourceSize, active, color, dpr, badge, rtl, weightScale, roughnessScale });
|
|
176
181
|
imageCache.set(key, image, canvasByteCost(image));
|
|
177
182
|
}
|
|
178
183
|
canvas.width = image.width;
|
|
@@ -181,26 +186,19 @@ export const PencilIcon = forwardRef(function PencilIcon({ active = false, badge
|
|
|
181
186
|
if (!context || context.isContextLost?.())
|
|
182
187
|
return;
|
|
183
188
|
context.drawImage(image, 0, 0);
|
|
184
|
-
|
|
189
|
+
lastPaintRef.current = key;
|
|
185
190
|
};
|
|
186
|
-
const appearance = new MutationObserver(paint);
|
|
187
|
-
appearance.observe(document.documentElement, {
|
|
188
|
-
attributes: true,
|
|
189
|
-
subtree: true,
|
|
190
|
-
attributeFilter: ['data-theme', 'data-inkra-theme'],
|
|
191
|
-
});
|
|
192
191
|
const inheritedColor = new MutationObserver(paint);
|
|
193
192
|
for (let element = canvas; element; element = element.parentElement) {
|
|
194
|
-
inheritedColor.observe(element, { attributes: true, attributeFilter: ['style', 'class', 'dir'] });
|
|
193
|
+
inheritedColor.observe(element, { attributes: true, attributeFilter: ['style', 'class', 'dir', 'data-theme', 'data-inkra-theme'] });
|
|
195
194
|
}
|
|
196
195
|
const colorScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
|
197
196
|
colorScheme.addEventListener('change', paint);
|
|
198
|
-
const stopRecovery = observeCanvasRecovery(() => {
|
|
197
|
+
const stopRecovery = observeCanvasRecovery(() => { lastPaintRef.current = ''; paint(); });
|
|
199
198
|
paint();
|
|
200
199
|
return () => {
|
|
201
200
|
disposed = true;
|
|
202
201
|
stopRecovery();
|
|
203
|
-
appearance.disconnect();
|
|
204
202
|
inheritedColor.disconnect();
|
|
205
203
|
colorScheme.removeEventListener('change', paint);
|
|
206
204
|
};
|
package/dist/PencilLine.js
CHANGED
|
@@ -5,6 +5,7 @@ import { observeCanvasRecovery } from './internal/recovery.js';
|
|
|
5
5
|
import { seedToNumber } from './internal/random.js';
|
|
6
6
|
import { createPencilLinePoints, pencilLineHasDrawableSize } from './internal/line.js';
|
|
7
7
|
import { pencilStroke } from './internal/stroke.js';
|
|
8
|
+
import { maxStrokeRoughness, pencilRenderDefaults, readRenderToken } from './internal/renderTokens.js';
|
|
8
9
|
const lineCache = new BoundedCache(96, 12 * 1024 * 1024);
|
|
9
10
|
function renderLine(width, height, color, seed, weight, roughness, orientation, dpr) {
|
|
10
11
|
const canvas = document.createElement('canvas');
|
|
@@ -17,7 +18,7 @@ function renderLine(width, height, color, seed, weight, roughness, orientation,
|
|
|
17
18
|
pencilStroke(context, createPencilLinePoints(width, height, orientation, roughness), color, weight, seed, roughness, 3, false, { variation: 0.82, breaks: 0.18, grain: 0.68, gain: 2.6, step: 0.5, taperLength: 1.4 });
|
|
18
19
|
return canvas;
|
|
19
20
|
}
|
|
20
|
-
export const PencilLine = forwardRef(function PencilLine({ className = '', orientation = 'horizontal', roughness
|
|
21
|
+
export const PencilLine = forwardRef(function PencilLine({ className = '', orientation = 'horizontal', roughness, seed = 'inkra-pencil-line', weight, ...props }, forwardedRef) {
|
|
21
22
|
const canvasRef = useRef(null);
|
|
22
23
|
useImperativeHandle(forwardedRef, () => canvasRef.current);
|
|
23
24
|
useEffect(() => {
|
|
@@ -26,6 +27,7 @@ export const PencilLine = forwardRef(function PencilLine({ className = '', orien
|
|
|
26
27
|
return undefined;
|
|
27
28
|
let frame = 0;
|
|
28
29
|
let disposed = false;
|
|
30
|
+
let lastPaint = '';
|
|
29
31
|
const paint = () => {
|
|
30
32
|
frame = 0;
|
|
31
33
|
if (disposed)
|
|
@@ -35,18 +37,23 @@ export const PencilLine = forwardRef(function PencilLine({ className = '', orien
|
|
|
35
37
|
if (!pencilLineHasDrawableSize(width, height, orientation))
|
|
36
38
|
return;
|
|
37
39
|
const dpr = effectiveDpr(2);
|
|
38
|
-
const
|
|
40
|
+
const style = getComputedStyle(canvas);
|
|
41
|
+
const color = style.color;
|
|
42
|
+
const resolvedWeight = weight ?? readRenderToken(style, '--inkra-stroke-width', pencilRenderDefaults.strokeWidth, 0.3, 3);
|
|
43
|
+
const resolvedRoughness = roughness ?? readRenderToken(style, '--inkra-stroke-amplitude', pencilRenderDefaults.strokeRoughness, 0, maxStrokeRoughness);
|
|
39
44
|
const numericSeed = seedToNumber(seed);
|
|
40
45
|
const key = JSON.stringify([
|
|
41
|
-
PENCIL_RENDERER_VERSION, orientation, width, height, color, numericSeed,
|
|
46
|
+
PENCIL_RENDERER_VERSION, orientation, width, height, color, numericSeed, resolvedWeight, resolvedRoughness, dpr,
|
|
42
47
|
]);
|
|
48
|
+
if (key === lastPaint && canvasIsUsable(canvas))
|
|
49
|
+
return;
|
|
43
50
|
let image = lineCache.get(key);
|
|
44
51
|
if (image && !canvasIsUsable(image)) {
|
|
45
52
|
lineCache.delete(key);
|
|
46
53
|
image = undefined;
|
|
47
54
|
}
|
|
48
55
|
if (!image) {
|
|
49
|
-
image = renderLine(width, height, color, numericSeed,
|
|
56
|
+
image = renderLine(width, height, color, numericSeed, resolvedWeight, resolvedRoughness, orientation, dpr);
|
|
50
57
|
lineCache.set(key, image, canvasByteCost(image));
|
|
51
58
|
}
|
|
52
59
|
canvas.width = image.width;
|
|
@@ -55,6 +62,7 @@ export const PencilLine = forwardRef(function PencilLine({ className = '', orien
|
|
|
55
62
|
if (!context || context.isContextLost?.())
|
|
56
63
|
return;
|
|
57
64
|
context.drawImage(image, 0, 0);
|
|
65
|
+
lastPaint = key;
|
|
58
66
|
};
|
|
59
67
|
const schedule = () => {
|
|
60
68
|
if (!frame)
|
|
@@ -62,21 +70,19 @@ export const PencilLine = forwardRef(function PencilLine({ className = '', orien
|
|
|
62
70
|
};
|
|
63
71
|
const resize = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(schedule);
|
|
64
72
|
resize?.observe(canvas);
|
|
65
|
-
const appearance = new MutationObserver(schedule);
|
|
66
|
-
appearance.observe(document.documentElement, {
|
|
67
|
-
attributes: true,
|
|
68
|
-
subtree: true,
|
|
69
|
-
attributeFilter: ['data-theme', 'data-inkra-theme'],
|
|
70
|
-
});
|
|
71
73
|
const colorScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
|
74
|
+
const inheritedStyle = new MutationObserver(schedule);
|
|
75
|
+
for (let element = canvas; element; element = element.parentElement) {
|
|
76
|
+
inheritedStyle.observe(element, { attributes: true, attributeFilter: ['style', 'class', 'data-theme', 'data-inkra-theme'] });
|
|
77
|
+
}
|
|
72
78
|
colorScheme.addEventListener('change', schedule);
|
|
73
|
-
const stopRecovery = observeCanvasRecovery(schedule);
|
|
79
|
+
const stopRecovery = observeCanvasRecovery(() => { lastPaint = ''; schedule(); });
|
|
74
80
|
paint();
|
|
75
81
|
return () => {
|
|
76
82
|
disposed = true;
|
|
77
83
|
stopRecovery();
|
|
78
84
|
resize?.disconnect();
|
|
79
|
-
|
|
85
|
+
inheritedStyle.disconnect();
|
|
80
86
|
colorScheme.removeEventListener('change', schedule);
|
|
81
87
|
cancelAnimationFrame(frame);
|
|
82
88
|
};
|