@xeplr/ui-factory 1.8.4 → 1.8.5
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 +1 -0
- package/package.json +1 -1
- package/src/buttons.js +11 -0
- package/src/designs/ButtonsView.jsx +2 -1
- package/src/designs/PropertyPanel.jsx +1 -0
- package/src/designs/factory.css +4 -0
- package/src/model.js +1 -1
- package/src/useFactoryScreen.js +2 -2
- package/src/validateDocument.js +2 -2
package/README.md
CHANGED
|
@@ -433,6 +433,7 @@ actions.register({
|
|
|
433
433
|
| `ask` | asked first: `title`, `message`, and `note` — the label of a note box, whose text reaches the function as `note` (it must take one) |
|
|
434
434
|
| `when` | shown only when every rule matches the record |
|
|
435
435
|
| `disabledWhen` | greyed out when every rule matches |
|
|
436
|
+
| `pressedWhen` | drawn as the **current choice** (filled, `aria-pressed`) when every rule matches — the status an order is at. Give it the same rules as `disabledWhen` when choosing it again would change nothing |
|
|
436
437
|
| `variant` | `default`, `primary`, `danger` |
|
|
437
438
|
|
|
438
439
|
Rules are [`@xeplr/rules`](https://www.npmjs.com/package/@xeplr/rules) rules — `{ field, op, value }`, with `eq`, `neq`, `isEmpty`, `contains`, `gt`, … — read from **the record the screen is about**: the `record` handed to `<FactoryScreen>`, with the form's own changes on top.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xeplr/ui-factory",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.5",
|
|
4
4
|
"description": "Design data-entry screens on @xeplr/ui-canvas, save them as JSON, run them as auto-saving forms with lists of saved records — built for Claude to draft and people to refine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/buttons.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
//
|
|
8
8
|
// { id: 'packed', label: 'Packed', action: 'setOrderStatus', params: { status: 'packed' },
|
|
9
9
|
// ask: { title: 'Change status to Packed', note: 'Reason (optional)' },
|
|
10
|
+
// pressedWhen: [{ field: 'customStatus', op: 'eq', value: 'packed' }],
|
|
10
11
|
// disabledWhen: [{ field: 'customStatus', op: 'eq', value: 'packed' }] }
|
|
11
12
|
//
|
|
12
13
|
// The function lives in the app, registered with @xeplr/actions and an
|
|
@@ -66,6 +67,16 @@ export function buttonDisabled(button, record) {
|
|
|
66
67
|
return Array.isArray(rules) && rules.length > 0 && conditionMet(rules, record)
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Whether a button is drawn as the CURRENT choice — the status an order is
|
|
72
|
+
* at, filled in. Usually also its disabledWhen: choosing it again changes
|
|
73
|
+
* nothing. No pressedWhen: never.
|
|
74
|
+
*/
|
|
75
|
+
export function buttonPressed(button, record) {
|
|
76
|
+
const rules = button && button.pressedWhen
|
|
77
|
+
return Array.isArray(rules) && rules.length > 0 && conditionMet(rules, record)
|
|
78
|
+
}
|
|
79
|
+
|
|
69
80
|
/** Every button on a screen, with the panel it is on. */
|
|
70
81
|
export function screenButtons(doc) {
|
|
71
82
|
return ((doc && doc.nodes) || [])
|
|
@@ -37,7 +37,8 @@ export default function ButtonsView({ node, design, panel }) {
|
|
|
37
37
|
<button
|
|
38
38
|
key={b.id}
|
|
39
39
|
type="button"
|
|
40
|
-
className={`xeplr-factory-button xeplr-factory-button--${b.variant || 'default'}`}
|
|
40
|
+
className={`xeplr-factory-button xeplr-factory-button--${b.variant || 'default'}${b.pressed ? ' xeplr-factory-button--pressed' : ''}`}
|
|
41
|
+
aria-pressed={b.pressedWhen ? Boolean(b.pressed) : undefined}
|
|
41
42
|
disabled={b.disabled || Boolean(panel.pressing)}
|
|
42
43
|
aria-busy={panel.pressing === b.id}
|
|
43
44
|
onClick={() => run(b)}
|
|
@@ -985,6 +985,7 @@ function ButtonsEditor({ value, onChange, functions }) {
|
|
|
985
985
|
)}
|
|
986
986
|
<ConditionsEditor label="Shows when" value={b.when} onChange={(v) => edit(i, { when: v })} />
|
|
987
987
|
<ConditionsEditor label="Greyed out when" value={b.disabledWhen} onChange={(v) => edit(i, { disabledWhen: v })} />
|
|
988
|
+
<ConditionsEditor label="Shown as the current choice when" value={b.pressedWhen} onChange={(v) => edit(i, { pressedWhen: v })} />
|
|
988
989
|
<MiniField label="Look">
|
|
989
990
|
<select className="xeplr-factory-prop-input" value={b.variant || 'default'} onChange={(e) => edit(i, { variant: e.target.value === 'default' ? undefined : e.target.value })}>
|
|
990
991
|
{BUTTON_VARIANTS.map((v) => <option key={v} value={v}>{VARIANT_LABELS[v]}</option>)}
|
package/src/designs/factory.css
CHANGED
|
@@ -372,6 +372,10 @@ button.xeplr-factory-activity-item:hover, button.xeplr-factory-activity-item:foc
|
|
|
372
372
|
.xeplr-factory-button--danger { color: var(--xf-danger); border-color: color-mix(in srgb, var(--xf-danger) 55%, var(--xf-border)); }
|
|
373
373
|
.xeplr-factory-button--danger:hover:not(:disabled) { background: color-mix(in srgb, var(--xf-danger) 10%, transparent); }
|
|
374
374
|
.xeplr-factory-buttons--design .xeplr-factory-button { cursor: inherit; }
|
|
375
|
+
/* The current choice (pressedWhen): filled, and never faded — greyed out is
|
|
376
|
+
"unavailable", which the current status is not. */
|
|
377
|
+
.xeplr-factory-button--pressed,
|
|
378
|
+
.xeplr-factory-button--pressed:disabled { color: var(--xf-accent-ink); background: var(--xf-accent); border-color: var(--xf-accent); opacity: 1; }
|
|
375
379
|
.xeplr-factory-buttons-note {
|
|
376
380
|
display: inline-flex; align-items: center; gap: 6px; font-size: .9em; padding: 4px 6px 4px 10px; border-radius: 6px;
|
|
377
381
|
color: var(--xf-good); background: color-mix(in srgb, var(--xf-good) 10%, transparent);
|
package/src/model.js
CHANGED
|
@@ -17,7 +17,7 @@ export { SCREEN_EVENTS, SCREEN_EVENT_KEYS, DECIDE_EVENT, FUNCTION_NAME, screenFu
|
|
|
17
17
|
// Buttons and lists whose rows a function works out — names and values only.
|
|
18
18
|
export {
|
|
19
19
|
BUTTON_EVENT, LIST_ROWS_EVENT, ROW_DETAILS_EVENT, BUTTON_VARIANTS, COLUMN_DISPLAYS, BADGE_TONES, NOTE_INPUT, CONDITION_OPERATORS,
|
|
20
|
-
conditionMet, buttonShown, buttonDisabled, screenButtons, buttonById, buttonInput, nodeFunctions, paramProblems, optionValues
|
|
20
|
+
conditionMet, buttonShown, buttonDisabled, buttonPressed, screenButtons, buttonById, buttonInput, nodeFunctions, paramProblems, optionValues
|
|
21
21
|
} from './buttons.js'
|
|
22
22
|
// Which pages are drawn from documents and which are web only (ui/pages.json).
|
|
23
23
|
export { checkInventory, routesIn, pageWarnings, webOnlyMenus } from './pagesInventory.js'
|
package/src/useFactoryScreen.js
CHANGED
|
@@ -5,7 +5,7 @@ import { validateDocument } from './validateDocument.js'
|
|
|
5
5
|
import { initialValues, parseInput, saveState, fieldError, optionValue, recordValues, listSource, resolveBinding } from './values.js'
|
|
6
6
|
import { hookMethod } from './hooks.js'
|
|
7
7
|
import { useUrlSteps, useUrlListQuery } from './useUrlPlaces.js'
|
|
8
|
-
import { buttonShown, buttonDisabled } from './buttons.js'
|
|
8
|
+
import { buttonShown, buttonDisabled, buttonPressed } from './buttons.js'
|
|
9
9
|
|
|
10
10
|
// A saved screen, running. No JSX — designs/ScreenSample.jsx draws it.
|
|
11
11
|
//
|
|
@@ -838,7 +838,7 @@ export function useFactoryScreen({
|
|
|
838
838
|
record: buttonRecord,
|
|
839
839
|
buttons: ((node.props && node.props.buttons) || [])
|
|
840
840
|
.filter((b) => buttonShown(b, buttonRecord))
|
|
841
|
-
.map((b) => ({ ...b, disabled: buttonDisabled(b, buttonRecord) || recordId === null || recordId === undefined })),
|
|
841
|
+
.map((b) => ({ ...b, pressed: buttonPressed(b, buttonRecord), disabled: buttonDisabled(b, buttonRecord) || recordId === null || recordId === undefined })),
|
|
842
842
|
pressing,
|
|
843
843
|
note: buttonNote,
|
|
844
844
|
clearNote: () => setButtonNote(null),
|
package/src/validateDocument.js
CHANGED
|
@@ -522,7 +522,7 @@ function checkFedColumn(c, p, err) {
|
|
|
522
522
|
}
|
|
523
523
|
}
|
|
524
524
|
|
|
525
|
-
const BUTTON_KEYS = ['id', 'label', 'action', 'params', 'ask', 'when', 'disabledWhen', 'variant']
|
|
525
|
+
const BUTTON_KEYS = ['id', 'label', 'action', 'params', 'ask', 'when', 'disabledWhen', 'pressedWhen', 'variant']
|
|
526
526
|
const ASK_KEYS = ['title', 'message', 'note']
|
|
527
527
|
|
|
528
528
|
/**
|
|
@@ -559,7 +559,7 @@ function checkButtons(props, at, err, ids) {
|
|
|
559
559
|
}
|
|
560
560
|
}
|
|
561
561
|
if (b.variant !== undefined && !BUTTON_VARIANTS.includes(b.variant)) err(`${p}.variant`, `must be one of: ${BUTTON_VARIANTS.join(', ')}`)
|
|
562
|
-
;['when', 'disabledWhen'].forEach((k) => { if (b[k] !== undefined) checkRules(b[k], `${p}.${k}`, err) })
|
|
562
|
+
;['when', 'disabledWhen', 'pressedWhen'].forEach((k) => { if (b[k] !== undefined) checkRules(b[k], `${p}.${k}`, err) })
|
|
563
563
|
})
|
|
564
564
|
}
|
|
565
565
|
|