@lotics/ui 12.1.2 → 13.7.1
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/AGENTS.md +5 -0
- package/docs/catalog.md +75 -33
- package/docs/composition.md +61 -24
- package/docs/data_entry.md +19 -17
- package/docs/templates.md +71 -76
- package/examples/tpl_item_list.tsx +6 -7
- package/examples/tpl_record.tsx +131 -188
- package/examples/tpl_task_board.tsx +20 -22
- package/package.json +3 -2
- package/src/badge.tsx +26 -10
- package/src/checklist.tsx +1 -1
- package/src/detail_row.tsx +24 -8
- package/src/drawer.tsx +10 -2
- package/src/form_date_picker.tsx +2 -1
- package/src/form_field.tsx +23 -3
- package/src/form_picker.tsx +2 -1
- package/src/form_switch.tsx +16 -2
- package/src/form_text_input.tsx +4 -4
- package/src/inline_date_picker.tsx +19 -9
- package/src/inline_edit.tsx +43 -24
- package/src/inline_member_select.tsx +43 -10
- package/src/inline_number_input.tsx +4 -4
- package/src/inline_select.tsx +193 -87
- package/src/inline_text_input.tsx +4 -4
- package/src/inline_time_picker.tsx +4 -4
- package/src/inset.tsx +38 -0
- package/src/linked_record_box.tsx +102 -0
- package/src/number_input.tsx +1 -1
- package/src/radio_picker.tsx +18 -28
- package/src/text_input_field.tsx +3 -3
- package/examples/tpl_tasks.tsx +0 -456
- package/src/inline_tag_select.tsx +0 -140
package/docs/templates.md
CHANGED
|
@@ -41,8 +41,7 @@ the package index is [../AGENTS.md](../AGENTS.md).
|
|
|
41
41
|
| A register / consolidated work-list (browse, per-row action, bulk action) | `tpl_item_list` |
|
|
42
42
|
| A guided sequence of physical tasks (scan, confirm, next) | `tpl_pick` |
|
|
43
43
|
| Splitting one source amount across many targets | `tpl_allocate` |
|
|
44
|
-
| A record's create/edit surface — also the settings shape | `tpl_record` |
|
|
45
|
-
| A personal to-do list | `tpl_tasks` |
|
|
44
|
+
| A record's create/edit surface — also the settings shape (its Tasks section IS the canonical task pattern) | `tpl_record` |
|
|
46
45
|
| A team task board (inline-managed grouped table) | `tpl_task_board` |
|
|
47
46
|
| Financial statements | `tpl_statements` |
|
|
48
47
|
| A scoped lookup report with export | `tpl_report` |
|
|
@@ -65,34 +64,41 @@ Laws for any screen where a record's data is edited and a primary action produce
|
|
|
65
64
|
2. **Static shape.** The page never changes shape from output-selection state. Conditional
|
|
66
65
|
rendering is DATA-driven only (a control appears because two stored values differ), never
|
|
67
66
|
selection-driven. Relevance is an advisory `Callout` with a jump-to-section action — warn,
|
|
68
|
-
never hide, never hard-block. One sanctioned disclosure: a
|
|
69
|
-
editor
|
|
70
|
-
shape change — it edits the record field in place and
|
|
67
|
+
never hide, never hard-block. One sanctioned disclosure: a fill-what's-missing `Inset`
|
|
68
|
+
editor CO-LOCATED under a just-checked item is progressive disclosure of the gate, not
|
|
69
|
+
shape change — it edits the record field in place and clears once satisfied.
|
|
71
70
|
3. **Colocation & ownership.** Every output option (selections, print/export switches) lives in
|
|
72
71
|
the output section beside its action; a per-entity selection carries its owner's name in its
|
|
73
72
|
heading. Persisted record DATA never lives there — data belongs in data sections. Misfiled
|
|
74
73
|
data announces itself as callout special-cases; the exception disappearing is the sign the
|
|
75
74
|
model is right. (HOMING is what's forbidden, not repair: the output section may host a
|
|
76
|
-
|
|
77
|
-
shows the value — rendered only while
|
|
75
|
+
co-located fill editor that saves onto the record field — same storage, the field's home
|
|
76
|
+
row shows the value — rendered only while a checked output still lacks the field.)
|
|
78
77
|
4. **Resolved state.** Controls show the EFFECTIVE state, never raw storage: a derived/suggested
|
|
79
78
|
selection renders checked; the first manual change persists the full explicit set; a
|
|
80
79
|
reset-to-auto affordance appears only in explicit mode. What's shown = what happens.
|
|
81
80
|
5. **Decision budget.** Every user decision earns its place — derive it, default it, or
|
|
82
81
|
conditionally render it; ask only the underivable. Suggestions are one-tap-save chips; a
|
|
83
82
|
placeholder states the honest effective fallback (what actually happens when empty), never
|
|
84
|
-
an example that lies.
|
|
85
|
-
|
|
83
|
+
an example that lies. A status/stage is the canonical DERIVED value — computed from its
|
|
84
|
+
inputs (dates, rollups, amounts), never a `select` the user maintains: if a human must set
|
|
85
|
+
it by hand, it isn't a status.
|
|
86
|
+
6. **Right section per data kind.** Files live in the ONE Documents desk near the top — never a
|
|
87
|
+
`files`/`FilesEditor` field scattered into a stage or detail section (a record has a single
|
|
88
|
+
Documents desk; → the **Documents** section below). A history / payment / event schedule is
|
|
89
|
+
a plain DATED LIST (Text rows or a simple `Table`), never a `Timeline` — `Timeline` is a
|
|
90
|
+
genuine activity FEED (who changed what, when), not a schedule of payments.
|
|
91
|
+
7. **Header = identity + provenance.** Id, the key identifier, created-at. No metrics or badges
|
|
86
92
|
duplicating data a section already owns.
|
|
87
|
-
|
|
93
|
+
8. **Destructive placement.** Solid `danger`, bottom-left after the entity's fields, ONE
|
|
88
94
|
convention page-wide, confirmed by `Alert`. Never in a heading row, never one-tap.
|
|
89
|
-
|
|
95
|
+
9. **Create-then-refine.** An add is one click creating a draft edited in place — drafts render
|
|
90
96
|
as empty inline editors with placeholders, never as fake data. No type-a-name-then-click
|
|
91
97
|
forms.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
98
|
+
10. **Optimistic feedback.** Every edit echoes locally, saves in the background, reconciles on
|
|
99
|
+
refetch, reverts + surfaces on error. Silent success, loud failure — no persistent "saved"
|
|
100
|
+
chrome.
|
|
101
|
+
11. **Chrome discipline.** Kit spacing scale only; ONE divider rule (between sibling blocks,
|
|
96
102
|
never doubled with section hairlines, none trailing); no state-echo labels or filler
|
|
97
103
|
captions — explanations live in `info` popovers and empty states (→ [composition grammar
|
|
98
104
|
§Microcopy](./composition.md)). A "why" question about a control is answered by tracing
|
|
@@ -167,15 +173,18 @@ screens — register, per-row action, gated selection, and act-on-many in one. T
|
|
|
167
173
|
|
|
168
174
|
- **One toolbar row** — search + a status `Select` + facet `FilterChip`s LEFT, the New CTA
|
|
169
175
|
RIGHT; a light `SummaryLine` of the filtered view below.
|
|
170
|
-
- **A sortable, `Divider`-separated `Table`** where
|
|
171
|
-
row that can't take the bulk action gets a
|
|
172
|
-
|
|
173
|
-
|
|
176
|
+
- **A sortable, `Divider`-separated `Table`** where the record's KEY/identifier is the FIRST
|
|
177
|
+
column and every row carries a leading checkbox; a row that can't take the bulk action gets a
|
|
178
|
+
**disabled** checkbox (the same gating as any blocked line). A row's status is
|
|
179
|
+
`Badge variant="dot"` — never the tonal `Badge` (that's the drawer/header twin; → [composition
|
|
180
|
+
grammar §"Status indicators have a WEIGHT"](./composition.md)) — and the SAME dot vocabulary
|
|
181
|
+
drives the status facet. A per-row action `Button` (here Print) is the row's primary action in
|
|
182
|
+
the trailing column, `⋯` its overflow. A select-all band, footer totals + `Pagination`, and a
|
|
174
183
|
`FloatingActionBar` carrying the bulk action while rows are ticked.
|
|
175
184
|
- **A row press opens the PRODUCTION workspace `Drawer`**, which demonstrates the full
|
|
176
185
|
record-workspace anatomy section by section:
|
|
177
186
|
- **Details `DetailTable`** showing every inline field type — text, `InlineMemberSelect`,
|
|
178
|
-
dates incl. optional time, dot-select, money number,
|
|
187
|
+
dates incl. optional time, dot-select, money number, an `InlineSelect multi` tag field,
|
|
179
188
|
and `InlineStatic` + a System badge for read-only values. Detail rows earn trailing CTAs
|
|
180
189
|
where deserved (Phone → Call, Due → Today) — the case where `trailingWidth` IS set.
|
|
181
190
|
- **Linked records** — the customer's other records as `ListItem`s (title + description at
|
|
@@ -236,8 +245,8 @@ billing, and quick-capture templates. Top → bottom:
|
|
|
236
245
|
and `error` (derived, e.g. overdue Due) — always explicit, never an ⓘ; the inline editors
|
|
237
246
|
demo their own transient save error (a throwing `onSave`). The Classification group works
|
|
238
247
|
**the right-input-per-field law**: a field gets the control its SHAPE wants, never a
|
|
239
|
-
default text box — ≤5 exclusive options the user should see → `RadioPicker` (
|
|
240
|
-
|
|
248
|
+
default text box — ≤5 exclusive options the user should see → `RadioPicker` (a stacked
|
|
249
|
+
column of full-width choices), a longer closed list → `InlineSelect` (rich
|
|
241
250
|
options carry a description line, shown in the resting row too), a pick from a big
|
|
242
251
|
REGISTRY → `Combobox` (search is the input), a boolean → `CheckboxInput`; a DEPENDENT
|
|
243
252
|
field renders only while its parent value makes it real (no disabled ghost rows).
|
|
@@ -248,9 +257,15 @@ billing, and quick-capture templates. Top → bottom:
|
|
|
248
257
|
file-capable edit form injected via `renderEditForm`) + THE kit `Composer` (attach via
|
|
249
258
|
`actionsButton`, staged files in its `files` slot) — never a bespoke comment box.
|
|
250
259
|
- **Tasks** — the full task-list grammar: clearable Group-by `FilterChip` (+ assignee/status
|
|
251
|
-
chips), the `CaptureRow` on top, `Checklist`/`ChecklistRow` rows
|
|
252
|
-
|
|
253
|
-
|
|
260
|
+
chips), the `CaptureRow` on top, `Checklist`/`ChecklistRow` rows and per-row menus,
|
|
261
|
+
suggestions as `SuggestionChip`s; groups divide via the `SubsectionStack` beat with plain
|
|
262
|
+
text heads (no dot badges). Each row's trailing carries **due + assignee as COMPACT grid CELLS** —
|
|
263
|
+
the SAME `InlineDatePicker` / `InlineMemberSelect` used in the General section, in **`variant="cell"`**
|
|
264
|
+
(transparent rest + wash on hover, no glyph/chevron): the due a urgency-coloured date (`tone`
|
|
265
|
+
= `dueTone` — red past due, amber ≤3d, else muted), the assignee an **`avatarOnly`** bare avatar
|
|
266
|
+
(dashed add-ghost when unset), sized to the list's `trailingWidth` so the title never overlaps.
|
|
267
|
+
(Contrast the General section's dates/assignee, the same editors in the default `variant="form"`
|
|
268
|
+
— a zinc-50 chip + hover-border + the full member chip.)
|
|
254
269
|
- **Documents** — the Agents "Document desk" pattern (shared with `tpl_documents` — change
|
|
255
270
|
it in BOTH): the register `Table` (search · Add files) whose selection feeds the
|
|
256
271
|
`FloatingActionBar` → ONE "Use AI" fork (extract / cross-check / edit-with-AI). Every
|
|
@@ -260,13 +275,13 @@ billing, and quick-capture templates. Top → bottom:
|
|
|
260
275
|
sanctioned divergence: GENERATION — on the record page this desk holds what ARRIVES and
|
|
261
276
|
Create moves to the Document set OUTPUT section below; `tpl_documents` (no output
|
|
262
277
|
pipeline on its page) keeps the toolbar "Create documents" dialog.
|
|
263
|
-
- **Customer — the LINKED-RECORD reference
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
278
|
+
- **Customer — the LINKED-RECORD reference** via **`LinkedRecordBox`**: another record's data
|
|
279
|
+
NEVER renders as field rows on this one — a BORDERED, fully pressable box (glyph anchor ·
|
|
280
|
+
identity · facts stacked VERTICALLY) whose press opens the detail drawer; the verbs ride the
|
|
281
|
+
`actions` slot INSIDE the box — destructive (Remove, `danger`) LEFT, go-to (Open record)
|
|
282
|
+
RIGHT. The component owns the keyboard-door a11y contract (never `role="button"` on the box —
|
|
283
|
+
see [composition.md's linked-record law](./composition.md)); the template supplies the icon,
|
|
284
|
+
facts, and localized verbs.
|
|
270
285
|
Empty state = the find-or-create search, custom row → the create `Dialog` (tax ID + Fetch;
|
|
271
286
|
its field errors ride `DetailRow error`, not a loose line).
|
|
272
287
|
- **Fees — the DETAILED money ledger** (both directions), distinct from Billing's invoice
|
|
@@ -301,24 +316,19 @@ billing, and quick-capture templates. Top → bottom:
|
|
|
301
316
|
consumers ("printed on the delivery note"). The picker rows ride `Checklist`/
|
|
302
317
|
`ChecklistRow` (`controlWidth={24}` for the `CheckboxInput`) — the compound owns the row
|
|
303
318
|
geometry and the `meta`/`expansion` indent; hand-rolling the anatomy is how alignment
|
|
304
|
-
drifts.
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
DEGRADED-BUT-VALID case (those fields print blank, filled by hand later): Create stays
|
|
318
|
-
ENABLED, the co-located warning `Callout` states the consequence ("… print blank unless
|
|
319
|
-
filled above"), and the press CONFIRMS via `Alert` — per-form "form — fields" lines,
|
|
320
|
-
Cancel back to the inline fixes / "Generate anyway". Only an empty pick disables, and
|
|
321
|
-
silently. A form can also be DATA-conditional (the hazardous-goods note renders only
|
|
319
|
+
drifts. Warning and fix are CO-LOCATED on the row. The mark NAMES what's missing (the
|
|
320
|
+
`meta` line: 13px `circle-alert` + "Needs: …" the actual field labels — muted at rest so
|
|
321
|
+
gaps show WITHOUT checking, warning once checked because it now blocks). The FIX sits
|
|
322
|
+
right under it in the row's `expansion` — an `Inset` (a FORM surface, NEVER a `Callout`:
|
|
323
|
+
a warning Callout is an ARIA `alert`, wrong around a form) with a `FormTextInput` per gap
|
|
324
|
+
(label + the consumer hint as `description`) and a "Save fields" (secondary — the section
|
|
325
|
+
keeps ONE primary, disabled while every draft is empty). Save writes the record fields
|
|
326
|
+
(their home rows show the values); the need resolves, the mark clears, the fill drops
|
|
327
|
+
away. Drafts are keyed BY FIELD, so a field two checked forms share is entered ONCE and
|
|
328
|
+
one Save resolves both. A ready form stays SILENT. Missing fields are the gating law's
|
|
329
|
+
DEGRADED-BUT-VALID case (they print blank, filled by hand later): Create stays ENABLED, a
|
|
330
|
+
co-located warning `Callout` states the consequence, and the press CONFIRMS via `Alert`.
|
|
331
|
+
Only an empty pick disables, and silently. A form can also be DATA-conditional (the hazardous-goods note renders only
|
|
322
332
|
while the record's Hazardous goods boolean is set — record data may reshape the list,
|
|
323
333
|
output selection never does).
|
|
324
334
|
- **Delivery receipt — the QUICK-ISSUE form, its OWN section** (in the rail): one document
|
|
@@ -363,29 +373,13 @@ billing, and quick-capture templates. Top → bottom:
|
|
|
363
373
|
below that it collapses to the pinned bar. Sizing the column is the SHELL's job — inner
|
|
364
374
|
blocks are plain `width: "100%"`, never a second `maxWidth` + `alignSelf: "center"`.
|
|
365
375
|
|
|
366
|
-
### `tpl_tasks` — the quick list
|
|
367
|
-
|
|
368
|
-
The personal to-do shape: quiet `CheckCircle` rows you tick to finish and tap to **expand in
|
|
369
|
-
place** to edit (`Inline*` editors; the row is stable — the meta summary never shifts on
|
|
370
|
-
expand), colour-dot tags (`OptionBadge`), an attachments field (`FilesEditor` — thumbnail
|
|
371
|
-
grid, tap a tile for the gallery with download + confirmed remove, plus its Add button),
|
|
372
|
-
search + a clearable group-by (✕ → ungrouped) + tag filter chips, and a primary
|
|
373
|
-
Draft-from-notes CTA (`Composer` → `AgentRun` → `ChangeReview`). No assignee — the list is
|
|
374
|
-
yours.
|
|
375
|
-
|
|
376
|
-
**Warning — never a button in a button.** There is deliberately NO `Task` component: a task
|
|
377
|
-
row varies too much to bake into one, so rows compose `CheckCircle` + `InlineTextInput` +
|
|
378
|
-
inline-editor cells as **sibling** controls in a plain `View`. NEVER wrap the whole row in a
|
|
379
|
-
`Pressable accessibilityRole="button"` (for tap-to-expand) with those controls nested inside:
|
|
380
|
-
React Native Web renders the row AND each control as a `<button>`, so you get `<button>`s
|
|
381
|
-
inside a `<button>` — invalid DOM, and the inner controls drop out of the keyboard tab order.
|
|
382
|
-
Give "expand" its own affordance (a trailing `Pressable` over the meta/chevron), as
|
|
383
|
-
`tpl_tasks` does.
|
|
384
|
-
|
|
385
376
|
### `tpl_task_board` — the columns shape
|
|
386
377
|
|
|
387
378
|
The manager's board: a search · group-by · filter toolbar over a grouped, sortable grid of
|
|
388
|
-
LIVE
|
|
379
|
+
LIVE editable cells — assignee/due/status/tags ALL via `Inline*` editors in **`variant="cell"`**
|
|
380
|
+
(`InlineMemberSelect` · `InlineDatePicker` · `InlineSelect`, and tags an `InlineSelect multi
|
|
381
|
+
allowCustom` — create-a-tag included), set directly in the cell. Every editable cell + the custom
|
|
382
|
+
Files/Action cells share ONE hover language (the `zinc-100` wash); no cell reveals a border. It builds on
|
|
389
383
|
the `DataGrid` primitive (the inline-managed grouped-table shape) and **owns only its data,
|
|
390
384
|
toolbar, columns, and per-group add**; `DataGrid` owns the sortable header, the collapsible
|
|
391
385
|
grouped sections, and the aligned rows. It demonstrates:
|
|
@@ -397,14 +391,15 @@ grouped sections, and the aligned rows. It demonstrates:
|
|
|
397
391
|
workflow: one board, a different action per row; the link's pressable fills the cell to
|
|
398
392
|
match the inline editors.
|
|
399
393
|
- A trailing `ActionMenu` (the `⋯` overflow — a `danger` Remove behind a confirm `Alert`).
|
|
400
|
-
- CUSTOM pressable cells (files, the action link) hover with the
|
|
401
|
-
|
|
402
|
-
|
|
394
|
+
- CUSTOM pressable cells (files, the action link) hover with the **background-tint WASH**
|
|
395
|
+
(`zinc-100`) — the standard CELL language, matching the `variant="cell"` editors beside them.
|
|
396
|
+
(A `variant="form"` editor reveals a border; a `variant="cell"` editor uses the wash — the two
|
|
397
|
+
hover languages, one per surface.)
|
|
403
398
|
- Per-group add rows that pre-set the group's field (align with the exported `gridRowStyle`),
|
|
404
|
-
and
|
|
399
|
+
and a Draft-from-notes CTA.
|
|
405
400
|
|
|
406
|
-
|
|
407
|
-
|
|
401
|
+
`tpl_task_board`: filters/search left, primary CTA right, one toolbar row; group-by holds
|
|
402
|
+
only real dimensions, ✕ clears to ungrouped (no "Nothing" option).
|
|
408
403
|
|
|
409
404
|
**Altitude rule**: `tpl_task_board` is the inline-managed grouped table — MODERATE data you
|
|
410
405
|
manage in view (group/sort/filter/edit-in-place; it renders ALL rows). For thousands+ you
|
|
@@ -56,7 +56,6 @@ import { Callout, CalloutText } from "@lotics/ui/callout";
|
|
|
56
56
|
import { Timeline, type TimelineItem } from "@lotics/ui/timeline";
|
|
57
57
|
import { Link } from "@lotics/ui/link";
|
|
58
58
|
import { TextInputField } from "@lotics/ui/text_input_field";
|
|
59
|
-
import { InlineTagSelect } from "@lotics/ui/inline_tag_select";
|
|
60
59
|
import { Section, SectionHeading, SectionHeadingMeta, SectionHeadingTitle } from "@lotics/ui/section_heading";
|
|
61
60
|
import { DangerZone } from "@lotics/ui/danger_zone";
|
|
62
61
|
import { ChipGroup } from "@lotics/ui/chip_group";
|
|
@@ -209,7 +208,7 @@ function TasksChecklist({ tasks, onChange, suggestions, onDismissSuggestion }: {
|
|
|
209
208
|
<>
|
|
210
209
|
<View style={{ width: 150 }}>
|
|
211
210
|
<InlineMemberSelect
|
|
212
|
-
|
|
211
|
+
variant="cell"
|
|
213
212
|
members={MEMBERS}
|
|
214
213
|
value={t.assignee}
|
|
215
214
|
onSave={(m) => patch(t.id, { assignee: m })}
|
|
@@ -219,7 +218,7 @@ function TasksChecklist({ tasks, onChange, suggestions, onDismissSuggestion }: {
|
|
|
219
218
|
</View>
|
|
220
219
|
<View style={{ width: 130 }}>
|
|
221
220
|
<InlineDatePicker
|
|
222
|
-
|
|
221
|
+
variant="cell"
|
|
223
222
|
value={t.due}
|
|
224
223
|
onSave={(v) => patch(t.id, { due: v })}
|
|
225
224
|
placeholder="Set due…"
|
|
@@ -230,7 +229,7 @@ function TasksChecklist({ tasks, onChange, suggestions, onDismissSuggestion }: {
|
|
|
230
229
|
}
|
|
231
230
|
>
|
|
232
231
|
<InlineTextInput
|
|
233
|
-
|
|
232
|
+
variant="cell"
|
|
234
233
|
value={t.label}
|
|
235
234
|
onSave={(v) => patch(t.id, { label: v })}
|
|
236
235
|
struck={t.done}
|
|
@@ -618,11 +617,12 @@ function HoSoWorkspace({ hs, daThu, onPaid, tasks, onTasksChange, suggestions, o
|
|
|
618
617
|
<InlineNumberInput value={declared} onSave={persist(setDeclared)} min={0} format={(v) => (v == null ? "" : formatMoney(v))} accessibilityLabel="Declared value" />
|
|
619
618
|
</DetailRow>
|
|
620
619
|
<DetailRow label="Tags">
|
|
621
|
-
<
|
|
620
|
+
<InlineSelect
|
|
621
|
+
multi
|
|
622
622
|
value={tags}
|
|
623
623
|
onSave={persist(setTags)}
|
|
624
624
|
options={TAG_OPTIONS}
|
|
625
|
-
|
|
625
|
+
renderSelected={renderTagBadge}
|
|
626
626
|
placeholder="Add tags…"
|
|
627
627
|
accessibilityLabel="Tags"
|
|
628
628
|
/>
|
|
@@ -957,7 +957,6 @@ function RecordDrawer({ hs, daThu, onPaid, tasks, onTasksChange, suggestions, on
|
|
|
957
957
|
hs.khach
|
|
958
958
|
)
|
|
959
959
|
}
|
|
960
|
-
width={440}
|
|
961
960
|
onPrev={canGoBack ? undefined : onPrev}
|
|
962
961
|
onNext={canGoBack ? undefined : onNext}
|
|
963
962
|
position={canGoBack ? undefined : position}
|