@cssints/apg-specs 0.0.0-stage → 0.5.2
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/LICENSE +21 -0
- package/README.md +65 -2
- package/dist/apg/accordion.bridge.d.mts +35 -0
- package/dist/apg/accordion.bridge.mjs +326 -0
- package/dist/apg/accordion.model.json +8397 -0
- package/dist/apg/alert.bridge.d.mts +22 -0
- package/dist/apg/alert.bridge.mjs +86 -0
- package/dist/apg/alert.model.json +871 -0
- package/dist/apg/alertdialog.bridge.d.mts +21 -0
- package/dist/apg/alertdialog.bridge.mjs +221 -0
- package/dist/apg/alertdialog.model.json +5232 -0
- package/dist/apg/breadcrumb.bridge.d.mts +26 -0
- package/dist/apg/breadcrumb.bridge.mjs +120 -0
- package/dist/apg/breadcrumb.model.json +574 -0
- package/dist/apg/button.bridge.d.mts +35 -0
- package/dist/apg/button.bridge.mjs +208 -0
- package/dist/apg/button.model.json +5814 -0
- package/dist/apg/carousel.bridge.d.mts +44 -0
- package/dist/apg/carousel.bridge.mjs +262 -0
- package/dist/apg/carousel.model.json +8963 -0
- package/dist/apg/checkbox-group.bridge.d.mts +25 -0
- package/dist/apg/checkbox-group.bridge.mjs +276 -0
- package/dist/apg/checkbox-group.model.json +3863 -0
- package/dist/apg/checkbox.bridge.d.mts +34 -0
- package/dist/apg/checkbox.bridge.mjs +253 -0
- package/dist/apg/checkbox.model.json +3158 -0
- package/dist/apg/combobox-autocomplete.bridge.d.mts +14 -0
- package/dist/apg/combobox-autocomplete.bridge.mjs +326 -0
- package/dist/apg/combobox-autocomplete.model.json +11586 -0
- package/dist/apg/combobox-dialog.bridge.d.mts +17 -0
- package/dist/apg/combobox-dialog.bridge.mjs +250 -0
- package/dist/apg/combobox-dialog.model.json +8981 -0
- package/dist/apg/combobox-grid.bridge.d.mts +17 -0
- package/dist/apg/combobox-grid.bridge.mjs +227 -0
- package/dist/apg/combobox-grid.model.json +8554 -0
- package/dist/apg/combobox-select-only.bridge.d.mts +24 -0
- package/dist/apg/combobox-select-only.bridge.mjs +304 -0
- package/dist/apg/combobox-select-only.model.json +7846 -0
- package/dist/apg/combobox-tree.bridge.d.mts +17 -0
- package/dist/apg/combobox-tree.bridge.mjs +211 -0
- package/dist/apg/combobox-tree.model.json +9345 -0
- package/dist/apg/dialog-modal.bridge.d.mts +35 -0
- package/dist/apg/dialog-modal.bridge.mjs +186 -0
- package/dist/apg/dialog-modal.model.json +7580 -0
- package/dist/apg/disclosure.bridge.d.mts +25 -0
- package/dist/apg/disclosure.bridge.mjs +202 -0
- package/dist/apg/disclosure.model.json +4703 -0
- package/dist/apg/feed.bridge.d.mts +31 -0
- package/dist/apg/feed.bridge.mjs +246 -0
- package/dist/apg/feed.model.json +4523 -0
- package/dist/apg/grid-selection.bridge.d.mts +13 -0
- package/dist/apg/grid-selection.bridge.mjs +160 -0
- package/dist/apg/grid-selection.model.json +6974 -0
- package/dist/apg/grid-sort.bridge.d.mts +12 -0
- package/dist/apg/grid-sort.bridge.mjs +138 -0
- package/dist/apg/grid-sort.model.json +3799 -0
- package/dist/apg/grid.bridge.d.mts +54 -0
- package/dist/apg/grid.bridge.mjs +441 -0
- package/dist/apg/grid.model.json +3802 -0
- package/dist/apg/link.bridge.d.mts +24 -0
- package/dist/apg/link.bridge.mjs +126 -0
- package/dist/apg/link.model.json +694 -0
- package/dist/apg/listbox-multi.bridge.d.mts +10 -0
- package/dist/apg/listbox-multi.bridge.mjs +261 -0
- package/dist/apg/listbox-multi.model.json +10893 -0
- package/dist/apg/listbox-rearrangeable.bridge.d.mts +20 -0
- package/dist/apg/listbox-rearrangeable.bridge.mjs +237 -0
- package/dist/apg/listbox-rearrangeable.model.json +17592 -0
- package/dist/apg/listbox-shared.d.mts +58 -0
- package/dist/apg/listbox-shared.mjs +171 -0
- package/dist/apg/listbox-single.bridge.d.mts +10 -0
- package/dist/apg/listbox-single.bridge.mjs +196 -0
- package/dist/apg/listbox-single.model.json +8024 -0
- package/dist/apg/listbox-typeahead.bridge.d.mts +10 -0
- package/dist/apg/listbox-typeahead.bridge.mjs +153 -0
- package/dist/apg/listbox-typeahead.model.json +5615 -0
- package/dist/apg/menu-button.bridge.d.mts +29 -0
- package/dist/apg/menu-button.bridge.mjs +259 -0
- package/dist/apg/menu-button.model.json +5706 -0
- package/dist/apg/menu-checkable.bridge.d.mts +25 -0
- package/dist/apg/menu-checkable.bridge.mjs +226 -0
- package/dist/apg/menu-checkable.model.json +4277 -0
- package/dist/apg/menu-menubar.bridge.d.mts +27 -0
- package/dist/apg/menu-menubar.bridge.mjs +273 -0
- package/dist/apg/menu-menubar.model.json +9540 -0
- package/dist/apg/meter.bridge.d.mts +28 -0
- package/dist/apg/meter.bridge.mjs +159 -0
- package/dist/apg/meter.model.json +1185 -0
- package/dist/apg/player.bridge.d.mts +24 -0
- package/dist/apg/player.bridge.mjs +342 -0
- package/dist/apg/player.model.json +11013 -0
- package/dist/apg/radio.bridge.d.mts +35 -0
- package/dist/apg/radio.bridge.mjs +371 -0
- package/dist/apg/radio.model.json +5011 -0
- package/dist/apg/slider-multithumb.bridge.d.mts +34 -0
- package/dist/apg/slider-multithumb.bridge.mjs +365 -0
- package/dist/apg/slider-multithumb.model.json +5774 -0
- package/dist/apg/slider.bridge.d.mts +54 -0
- package/dist/apg/slider.bridge.mjs +359 -0
- package/dist/apg/slider.model.json +4881 -0
- package/dist/apg/spinbutton.bridge.d.mts +41 -0
- package/dist/apg/spinbutton.bridge.mjs +327 -0
- package/dist/apg/spinbutton.model.json +7571 -0
- package/dist/apg/switch.bridge.d.mts +30 -0
- package/dist/apg/switch.bridge.mjs +243 -0
- package/dist/apg/switch.model.json +3159 -0
- package/dist/apg/tabs.bridge.d.mts +41 -0
- package/dist/apg/tabs.bridge.mjs +294 -0
- package/dist/apg/tabs.model.json +7659 -0
- package/dist/apg/timeline.bridge.d.mts +36 -0
- package/dist/apg/timeline.bridge.mjs +265 -0
- package/dist/apg/timeline.model.json +6189 -0
- package/dist/apg/toolbar.bridge.d.mts +25 -0
- package/dist/apg/toolbar.bridge.mjs +307 -0
- package/dist/apg/toolbar.model.json +6616 -0
- package/dist/apg/tooltip.bridge.d.mts +36 -0
- package/dist/apg/tooltip.bridge.mjs +208 -0
- package/dist/apg/tooltip.model.json +8295 -0
- package/dist/apg/treegrid.bridge.d.mts +28 -0
- package/dist/apg/treegrid.bridge.mjs +311 -0
- package/dist/apg/treegrid.model.json +17358 -0
- package/dist/apg/treeview.bridge.d.mts +26 -0
- package/dist/apg/treeview.bridge.mjs +396 -0
- package/dist/apg/treeview.model.json +13745 -0
- package/dist/apg/windowsplitter.bridge.d.mts +36 -0
- package/dist/apg/windowsplitter.bridge.mjs +242 -0
- package/dist/apg/windowsplitter.model.json +6253 -0
- package/dist/canvas/camera.model.json +6568 -0
- package/dist/canvas/canvas.bridge.d.mts +190 -0
- package/dist/canvas/canvas.bridge.mjs +729 -0
- package/dist/canvas/pointer.model.json +17095 -0
- package/dist/scenario.d.mts +233 -0
- package/dist/scenario.mjs +313 -0
- package/package.json +57 -4
- package/scenarios/apg/README.md +221 -0
- package/scenarios/apg/accordion.base-ui.json +1005 -0
- package/scenarios/apg/accordion.react-aria.json +929 -0
- package/scenarios/apg/alert.base-ui.json +81 -0
- package/scenarios/apg/alert.react-aria.json +98 -0
- package/scenarios/apg/alertdialog.base-ui.json +331 -0
- package/scenarios/apg/alertdialog.react-aria.json +225 -0
- package/scenarios/apg/breadcrumb.react-aria.json +312 -0
- package/scenarios/apg/button.ariakit.json +136 -0
- package/scenarios/apg/button.base-ui.json +747 -0
- package/scenarios/apg/button.react-aria.json +443 -0
- package/scenarios/apg/carousel.apg.json +909 -0
- package/scenarios/apg/checkbox.ariakit.json +299 -0
- package/scenarios/apg/checkbox.base-ui.json +1126 -0
- package/scenarios/apg/checkbox.react-aria.json +518 -0
- package/scenarios/apg/combobox.ariakit.json +945 -0
- package/scenarios/apg/combobox.base-ui.json +2444 -0
- package/scenarios/apg/combobox.react-aria.json +845 -0
- package/scenarios/apg/dialog-modal.ariakit.json +1102 -0
- package/scenarios/apg/dialog-modal.base-ui.json +775 -0
- package/scenarios/apg/dialog-modal.react-aria.json +638 -0
- package/scenarios/apg/disclosure.apg.json +349 -0
- package/scenarios/apg/disclosure.ariakit.json +163 -0
- package/scenarios/apg/disclosure.base-ui.json +451 -0
- package/scenarios/apg/disclosure.react-aria.json +643 -0
- package/scenarios/apg/feed.apg.json +442 -0
- package/scenarios/apg/grid.ariakit.json +197 -0
- package/scenarios/apg/grid.base-ui.json +720 -0
- package/scenarios/apg/grid.react-aria.json +969 -0
- package/scenarios/apg/landmarks.ariakit.json +93 -0
- package/scenarios/apg/landmarks.react-aria.json +330 -0
- package/scenarios/apg/link.ariakit.json +83 -0
- package/scenarios/apg/link.base-ui.json +88 -0
- package/scenarios/apg/link.react-aria.json +186 -0
- package/scenarios/apg/listbox.ariakit.json +78 -0
- package/scenarios/apg/listbox.base-ui.json +163 -0
- package/scenarios/apg/listbox.react-aria.json +1118 -0
- package/scenarios/apg/menu-button.ariakit.json +924 -0
- package/scenarios/apg/menu-button.base-ui.json +1155 -0
- package/scenarios/apg/menu-button.react-aria.json +1080 -0
- package/scenarios/apg/menubar.ariakit.json +758 -0
- package/scenarios/apg/menubar.base-ui.json +673 -0
- package/scenarios/apg/meter.base-ui.json +243 -0
- package/scenarios/apg/meter.react-aria.json +201 -0
- package/scenarios/apg/radio.ariakit.json +459 -0
- package/scenarios/apg/radio.base-ui.json +581 -0
- package/scenarios/apg/radio.react-aria.json +576 -0
- package/scenarios/apg/slider-multithumb.base-ui.json +316 -0
- package/scenarios/apg/slider-multithumb.react-aria.json +363 -0
- package/scenarios/apg/slider.base-ui.json +544 -0
- package/scenarios/apg/slider.react-aria.json +456 -0
- package/scenarios/apg/spinbutton.base-ui.json +1688 -0
- package/scenarios/apg/spinbutton.react-aria.json +426 -0
- package/scenarios/apg/switch.base-ui.json +456 -0
- package/scenarios/apg/switch.react-aria.json +303 -0
- package/scenarios/apg/table.ariakit.json +65 -0
- package/scenarios/apg/table.react-aria.json +221 -0
- package/scenarios/apg/tabs.ariakit.json +329 -0
- package/scenarios/apg/tabs.base-ui.json +875 -0
- package/scenarios/apg/tabs.react-aria.json +644 -0
- package/scenarios/apg/toolbar.ariakit.json +595 -0
- package/scenarios/apg/toolbar.base-ui.json +1189 -0
- package/scenarios/apg/toolbar.react-aria.json +383 -0
- package/scenarios/apg/tooltip.ariakit.json +441 -0
- package/scenarios/apg/tooltip.base-ui.json +411 -0
- package/scenarios/apg/tooltip.react-aria.json +454 -0
- package/scenarios/apg/treegrid.apg.json +2558 -0
- package/scenarios/apg/treegrid.react-aria.json +5094 -0
- package/scenarios/apg/treeview.apg.json +928 -0
- package/scenarios/apg/windowsplitter.apg.json +557 -0
- package/scenarios/canvas/README.md +69 -0
- package/scenarios/canvas/camera.contract.json +237 -0
- package/scenarios/canvas/camera.excalidraw.json +57 -0
- package/scenarios/canvas/marquee.excalidraw.json +122 -0
- package/scenarios/canvas/pan.excalidraw.json +46 -0
- package/scenarios/canvas/pointer.contract.json +528 -0
- package/scenarios/parts.json +291 -0
- package/shared/aria.qnt +186 -0
- package/shared/details-group.qnt +50 -0
- package/shared/focusgroup.qnt +152 -0
- package/shared/invokers.qnt +81 -0
- package/shared/popover.qnt +71 -0
- package/specs/apg/STATIC.md +103 -0
- package/specs/apg/accordion.qnt +578 -0
- package/specs/apg/alert.qnt +131 -0
- package/specs/apg/alertdialog.qnt +455 -0
- package/specs/apg/breadcrumb.qnt +88 -0
- package/specs/apg/button.qnt +445 -0
- package/specs/apg/carousel.qnt +732 -0
- package/specs/apg/checkbox-group.qnt +388 -0
- package/specs/apg/checkbox.qnt +394 -0
- package/specs/apg/combobox-autocomplete.qnt +764 -0
- package/specs/apg/combobox-dialog.qnt +627 -0
- package/specs/apg/combobox-grid.qnt +632 -0
- package/specs/apg/combobox-select-only.qnt +626 -0
- package/specs/apg/combobox-tree.qnt +633 -0
- package/specs/apg/dialog-modal.qnt +499 -0
- package/specs/apg/disclosure.qnt +309 -0
- package/specs/apg/feed.qnt +485 -0
- package/specs/apg/grid-selection.qnt +512 -0
- package/specs/apg/grid-sort.qnt +330 -0
- package/specs/apg/grid.qnt +360 -0
- package/specs/apg/link.qnt +119 -0
- package/specs/apg/listbox-multi.qnt +799 -0
- package/specs/apg/listbox-rearrangeable.qnt +801 -0
- package/specs/apg/listbox-single.qnt +511 -0
- package/specs/apg/listbox-typeahead.qnt +396 -0
- package/specs/apg/menu-button.qnt +363 -0
- package/specs/apg/menu-checkable.qnt +304 -0
- package/specs/apg/menu-menubar.qnt +531 -0
- package/specs/apg/meter.qnt +129 -0
- package/specs/apg/player.qnt +1081 -0
- package/specs/apg/radio.qnt +394 -0
- package/specs/apg/slider-multithumb.qnt +441 -0
- package/specs/apg/slider.qnt +396 -0
- package/specs/apg/spinbutton.qnt +494 -0
- package/specs/apg/switch.qnt +389 -0
- package/specs/apg/tabs.qnt +412 -0
- package/specs/apg/timeline.qnt +612 -0
- package/specs/apg/toolbar.qnt +364 -0
- package/specs/apg/tooltip.qnt +553 -0
- package/specs/apg/treegrid.qnt +983 -0
- package/specs/apg/treeview.qnt +1004 -0
- package/specs/apg/windowsplitter.qnt +487 -0
- package/specs/canvas/camera.qnt +407 -0
- package/specs/canvas/pointer.qnt +841 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
// APG Window Splitter — https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/
|
|
2
|
+
//
|
|
3
|
+
// A role=separator that resizes the primary pane (aria-controls="primary").
|
|
4
|
+
// The spec models the widget state (`value`, `collapsed`, the remembered
|
|
5
|
+
// `prev`) and the rendered aria-valuenow (`ariaNow`); aria-valuemin / -max are
|
|
6
|
+
// the constants MIN / MAX below.
|
|
7
|
+
//
|
|
8
|
+
// Orientation names the splitter bar, as in APG: a "vertical" splitter sits
|
|
9
|
+
// between left/right panes (Left/Right move it), a "horizontal" one between
|
|
10
|
+
// top/bottom panes (Up/Down move it). Left/Up shrink the primary pane,
|
|
11
|
+
// Right/Down grow it.
|
|
12
|
+
//
|
|
13
|
+
// Events are the user-level alphabet shared with the scenario bridge:
|
|
14
|
+
// focusSplitter / blur the separator gains / loses focus
|
|
15
|
+
// left right up down arrow keys (only the pair matching the orientation moves)
|
|
16
|
+
// home end optional: jump to MIN / MAX
|
|
17
|
+
// enter toggle collapse; expanding restores the remembered value
|
|
18
|
+
// f6 optional: cycle focus splitter -> secondary -> primary -> splitter
|
|
19
|
+
// orientVertical / orientHorizontal / makeFixed / makeResizable prop changes
|
|
20
|
+
//
|
|
21
|
+
// A fixed splitter ignores arrows and Home/End: only Enter acts.
|
|
22
|
+
// While collapsed, arrows and Home/End are no-ops (collapsed => value == MIN).
|
|
23
|
+
//
|
|
24
|
+
// Request vs commit (map ticket rt1p). `value` (the primary pane size) is the
|
|
25
|
+
// controlled value: every movement — left, right, up, down, home, end, enter —
|
|
26
|
+
// is a *request* carrying its target (`requested`). It fires onValueChange
|
|
27
|
+
// (`requests` counts the calls) when the target differs from the current value,
|
|
28
|
+
// and then:
|
|
29
|
+
// uncontrolled the request is accepted: `value` commits the target
|
|
30
|
+
// controlled, holds the host ignores it ("rejected"): `value` is untouched
|
|
31
|
+
// controlled, accepts the host writes the target back (`accepting`)
|
|
32
|
+
// `valueProp` is the host's copy (meaningful while `controlled`); `setValue` /
|
|
33
|
+
// `hostToggle` are the host writing it, the only commit while controlled.
|
|
34
|
+
// `control` / `acceptRequests` configure the host (init is literal-only).
|
|
35
|
+
// Because collapse is entangled with `value`, its side effects (collapsed /
|
|
36
|
+
// prev / justRestored) are gated by the same rejection as the value commit.
|
|
37
|
+
//
|
|
38
|
+
// Invariants for the model: ControlledFollowsProp (in controlled mode no event
|
|
39
|
+
// commits), RejectedRequestUntouched, AcceptedRequestCommits.
|
|
40
|
+
//
|
|
41
|
+
// `outcome` is "none" | "accepted" | "rejected" for the last request; a host
|
|
42
|
+
// write settles it back to "none". `base` is the value when it was received.
|
|
43
|
+
//
|
|
44
|
+
// ponytail: F6 is always modelled (no on/off variant); dragging and a
|
|
45
|
+
// min-size above 0 are not modelled.
|
|
46
|
+
module apg_windowsplitter {
|
|
47
|
+
import aria.* from "../../shared/aria"
|
|
48
|
+
|
|
49
|
+
var orientation: str // "vertical" | "horizontal"
|
|
50
|
+
var fixed: bool // fixed splitter: only Enter acts
|
|
51
|
+
var value: int // primary pane size, MIN..MAX
|
|
52
|
+
var prev: int // value remembered at the last collapse
|
|
53
|
+
var collapsed: bool // primary pane is collapsed
|
|
54
|
+
var justRestored: bool // the last event was an Enter that restored `prev`
|
|
55
|
+
var focus: str // "none" | "splitter" | "primary" | "secondary"
|
|
56
|
+
var ariaNow: int // rendered aria-valuenow
|
|
57
|
+
var requests: int // number of requests that fired onValueChange
|
|
58
|
+
var controlled: bool // the host owns the value (`value` prop present)
|
|
59
|
+
var accepting: bool // controlled host that answers every request with its intent
|
|
60
|
+
var valueProp: int // the controlled value prop (meaningful while controlled)
|
|
61
|
+
var requested: int // target of the last request
|
|
62
|
+
var outcome: str // "none" | "accepted" | "rejected"
|
|
63
|
+
var base: int // value when the last request was received
|
|
64
|
+
|
|
65
|
+
def MIN: int = 0
|
|
66
|
+
def MAX: int = 6
|
|
67
|
+
def STEP: int = 2
|
|
68
|
+
def INITIAL: int = 4
|
|
69
|
+
|
|
70
|
+
def clamp(v: int): int = if (v < MIN) MIN else if (v > MAX) MAX else v
|
|
71
|
+
def movable: bool = and(focus == "splitter", and(not(fixed), not(collapsed)))
|
|
72
|
+
def arrowTarget(o: str, delta: int): int =
|
|
73
|
+
if (and(movable, orientation == o)) clamp(value + delta) else value
|
|
74
|
+
def homeTarget: int = if (movable) MIN else value
|
|
75
|
+
def endTarget: int = if (movable) MAX else value
|
|
76
|
+
def onSplitter: bool = focus == "splitter"
|
|
77
|
+
def f6Focus: str =
|
|
78
|
+
if (focus == "splitter") "secondary"
|
|
79
|
+
else if (focus == "secondary") "primary"
|
|
80
|
+
else if (focus == "primary") "splitter"
|
|
81
|
+
else "none"
|
|
82
|
+
def enterValue: int =
|
|
83
|
+
if (not(onSplitter)) value else if (collapsed) prev else MIN
|
|
84
|
+
|
|
85
|
+
// --- request / commit (map ticket rt1p) ----------------------------------
|
|
86
|
+
def moved(a: int, b: int): int = if (a == b) 0 else 1
|
|
87
|
+
def holds: bool = and(controlled, not(accepting))
|
|
88
|
+
def follows: bool = and(controlled, accepting)
|
|
89
|
+
def verdict: str = if (holds) "rejected" else "accepted"
|
|
90
|
+
// the value after a request for `want`
|
|
91
|
+
def landed(h: bool, v: int, want: int): int = if (h) v else want
|
|
92
|
+
// the value prop after a request for `want`
|
|
93
|
+
def propAfter(f: bool, p: int, want: int): int = if (f) want else p
|
|
94
|
+
// the target of each movement event
|
|
95
|
+
def wantLeft: int = arrowTarget("vertical", 0 - STEP)
|
|
96
|
+
def wantRight: int = arrowTarget("vertical", STEP)
|
|
97
|
+
def wantUp: int = arrowTarget("horizontal", 0 - STEP)
|
|
98
|
+
def wantDown: int = arrowTarget("horizontal", STEP)
|
|
99
|
+
def wantHome: int = homeTarget
|
|
100
|
+
def wantEnd: int = endTarget
|
|
101
|
+
def wantEnter: int = enterValue
|
|
102
|
+
// an Enter that would not move the value is not a rejected request: the
|
|
103
|
+
// collapse flag still flips (there is nothing for the host to veto)
|
|
104
|
+
def rejectEnter: bool = and(holds, value != wantEnter)
|
|
105
|
+
|
|
106
|
+
action init = all {
|
|
107
|
+
orientation' = "vertical",
|
|
108
|
+
fixed' = false,
|
|
109
|
+
value' = INITIAL,
|
|
110
|
+
prev' = INITIAL,
|
|
111
|
+
collapsed' = false,
|
|
112
|
+
justRestored' = false,
|
|
113
|
+
focus' = "none",
|
|
114
|
+
ariaNow' = INITIAL,
|
|
115
|
+
requests' = 0,
|
|
116
|
+
controlled' = false,
|
|
117
|
+
accepting' = false,
|
|
118
|
+
valueProp' = INITIAL,
|
|
119
|
+
requested' = INITIAL,
|
|
120
|
+
outcome' = "none",
|
|
121
|
+
base' = INITIAL
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
action focusSplitter = all {
|
|
125
|
+
orientation' = orientation,
|
|
126
|
+
fixed' = fixed,
|
|
127
|
+
value' = value,
|
|
128
|
+
prev' = prev,
|
|
129
|
+
collapsed' = collapsed,
|
|
130
|
+
justRestored' = false,
|
|
131
|
+
focus' = "splitter",
|
|
132
|
+
ariaNow' = ariaNow,
|
|
133
|
+
requests' = requests,
|
|
134
|
+
controlled' = controlled,
|
|
135
|
+
accepting' = accepting,
|
|
136
|
+
valueProp' = valueProp,
|
|
137
|
+
requested' = requested,
|
|
138
|
+
outcome' = outcome,
|
|
139
|
+
base' = base
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
action blur = all {
|
|
143
|
+
orientation' = orientation,
|
|
144
|
+
fixed' = fixed,
|
|
145
|
+
value' = value,
|
|
146
|
+
prev' = prev,
|
|
147
|
+
collapsed' = collapsed,
|
|
148
|
+
justRestored' = false,
|
|
149
|
+
focus' = "none",
|
|
150
|
+
ariaNow' = ariaNow,
|
|
151
|
+
requests' = requests,
|
|
152
|
+
controlled' = controlled,
|
|
153
|
+
accepting' = accepting,
|
|
154
|
+
valueProp' = valueProp,
|
|
155
|
+
requested' = requested,
|
|
156
|
+
outcome' = outcome,
|
|
157
|
+
base' = base
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// request: move left by one step
|
|
161
|
+
action left = all {
|
|
162
|
+
orientation' = orientation,
|
|
163
|
+
fixed' = fixed,
|
|
164
|
+
value' = landed(holds, value, wantLeft),
|
|
165
|
+
prev' = prev,
|
|
166
|
+
collapsed' = collapsed,
|
|
167
|
+
justRestored' = false,
|
|
168
|
+
focus' = focus,
|
|
169
|
+
ariaNow' = landed(holds, value, wantLeft),
|
|
170
|
+
requests' = requests + moved(value, wantLeft),
|
|
171
|
+
controlled' = controlled,
|
|
172
|
+
accepting' = accepting,
|
|
173
|
+
valueProp' = propAfter(follows, valueProp, wantLeft),
|
|
174
|
+
requested' = if (value == wantLeft) requested else wantLeft,
|
|
175
|
+
outcome' = if (value == wantLeft) outcome else verdict,
|
|
176
|
+
base' = if (value == wantLeft) base else value
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
action right = all {
|
|
180
|
+
orientation' = orientation,
|
|
181
|
+
fixed' = fixed,
|
|
182
|
+
value' = landed(holds, value, wantRight),
|
|
183
|
+
prev' = prev,
|
|
184
|
+
collapsed' = collapsed,
|
|
185
|
+
justRestored' = false,
|
|
186
|
+
focus' = focus,
|
|
187
|
+
ariaNow' = landed(holds, value, wantRight),
|
|
188
|
+
requests' = requests + moved(value, wantRight),
|
|
189
|
+
controlled' = controlled,
|
|
190
|
+
accepting' = accepting,
|
|
191
|
+
valueProp' = propAfter(follows, valueProp, wantRight),
|
|
192
|
+
requested' = if (value == wantRight) requested else wantRight,
|
|
193
|
+
outcome' = if (value == wantRight) outcome else verdict,
|
|
194
|
+
base' = if (value == wantRight) base else value
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
action up = all {
|
|
198
|
+
orientation' = orientation,
|
|
199
|
+
fixed' = fixed,
|
|
200
|
+
value' = landed(holds, value, wantUp),
|
|
201
|
+
prev' = prev,
|
|
202
|
+
collapsed' = collapsed,
|
|
203
|
+
justRestored' = false,
|
|
204
|
+
focus' = focus,
|
|
205
|
+
ariaNow' = landed(holds, value, wantUp),
|
|
206
|
+
requests' = requests + moved(value, wantUp),
|
|
207
|
+
controlled' = controlled,
|
|
208
|
+
accepting' = accepting,
|
|
209
|
+
valueProp' = propAfter(follows, valueProp, wantUp),
|
|
210
|
+
requested' = if (value == wantUp) requested else wantUp,
|
|
211
|
+
outcome' = if (value == wantUp) outcome else verdict,
|
|
212
|
+
base' = if (value == wantUp) base else value
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
action down = all {
|
|
216
|
+
orientation' = orientation,
|
|
217
|
+
fixed' = fixed,
|
|
218
|
+
value' = landed(holds, value, wantDown),
|
|
219
|
+
prev' = prev,
|
|
220
|
+
collapsed' = collapsed,
|
|
221
|
+
justRestored' = false,
|
|
222
|
+
focus' = focus,
|
|
223
|
+
ariaNow' = landed(holds, value, wantDown),
|
|
224
|
+
requests' = requests + moved(value, wantDown),
|
|
225
|
+
controlled' = controlled,
|
|
226
|
+
accepting' = accepting,
|
|
227
|
+
valueProp' = propAfter(follows, valueProp, wantDown),
|
|
228
|
+
requested' = if (value == wantDown) requested else wantDown,
|
|
229
|
+
outcome' = if (value == wantDown) outcome else verdict,
|
|
230
|
+
base' = if (value == wantDown) base else value
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
action home = all {
|
|
234
|
+
orientation' = orientation,
|
|
235
|
+
fixed' = fixed,
|
|
236
|
+
value' = landed(holds, value, wantHome),
|
|
237
|
+
prev' = prev,
|
|
238
|
+
collapsed' = collapsed,
|
|
239
|
+
justRestored' = false,
|
|
240
|
+
focus' = focus,
|
|
241
|
+
ariaNow' = landed(holds, value, wantHome),
|
|
242
|
+
requests' = requests + moved(value, wantHome),
|
|
243
|
+
controlled' = controlled,
|
|
244
|
+
accepting' = accepting,
|
|
245
|
+
valueProp' = propAfter(follows, valueProp, wantHome),
|
|
246
|
+
requested' = if (value == wantHome) requested else wantHome,
|
|
247
|
+
outcome' = if (value == wantHome) outcome else verdict,
|
|
248
|
+
base' = if (value == wantHome) base else value
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
action end = all {
|
|
252
|
+
orientation' = orientation,
|
|
253
|
+
fixed' = fixed,
|
|
254
|
+
value' = landed(holds, value, wantEnd),
|
|
255
|
+
prev' = prev,
|
|
256
|
+
collapsed' = collapsed,
|
|
257
|
+
justRestored' = false,
|
|
258
|
+
focus' = focus,
|
|
259
|
+
ariaNow' = landed(holds, value, wantEnd),
|
|
260
|
+
requests' = requests + moved(value, wantEnd),
|
|
261
|
+
controlled' = controlled,
|
|
262
|
+
accepting' = accepting,
|
|
263
|
+
valueProp' = propAfter(follows, valueProp, wantEnd),
|
|
264
|
+
requested' = if (value == wantEnd) requested else wantEnd,
|
|
265
|
+
outcome' = if (value == wantEnd) outcome else verdict,
|
|
266
|
+
base' = if (value == wantEnd) base else value
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// request: collapse remembers the current value; expanding restores it.
|
|
270
|
+
// A rejected request leaves collapsed / prev / justRestored untouched too.
|
|
271
|
+
action enter = all {
|
|
272
|
+
orientation' = orientation,
|
|
273
|
+
fixed' = fixed,
|
|
274
|
+
value' = landed(holds, value, wantEnter),
|
|
275
|
+
prev' = if (rejectEnter) prev else (if (and(onSplitter, not(collapsed))) value else prev),
|
|
276
|
+
collapsed' = if (rejectEnter) collapsed else (if (onSplitter) not(collapsed) else collapsed),
|
|
277
|
+
justRestored' = if (rejectEnter) justRestored else (and(onSplitter, collapsed)),
|
|
278
|
+
focus' = focus,
|
|
279
|
+
ariaNow' = landed(holds, value, wantEnter),
|
|
280
|
+
requests' = requests + moved(value, wantEnter),
|
|
281
|
+
controlled' = controlled,
|
|
282
|
+
accepting' = accepting,
|
|
283
|
+
valueProp' = propAfter(follows, valueProp, wantEnter),
|
|
284
|
+
requested' = if (value == wantEnter) requested else wantEnter,
|
|
285
|
+
outcome' = if (value == wantEnter) outcome else verdict,
|
|
286
|
+
base' = if (value == wantEnter) base else value
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
action f6 = all {
|
|
290
|
+
orientation' = orientation,
|
|
291
|
+
fixed' = fixed,
|
|
292
|
+
value' = value,
|
|
293
|
+
prev' = prev,
|
|
294
|
+
collapsed' = collapsed,
|
|
295
|
+
justRestored' = false,
|
|
296
|
+
focus' = f6Focus,
|
|
297
|
+
ariaNow' = ariaNow,
|
|
298
|
+
requests' = requests,
|
|
299
|
+
controlled' = controlled,
|
|
300
|
+
accepting' = accepting,
|
|
301
|
+
valueProp' = valueProp,
|
|
302
|
+
requested' = requested,
|
|
303
|
+
outcome' = outcome,
|
|
304
|
+
base' = base
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
action orientVertical = all {
|
|
308
|
+
orientation' = "vertical",
|
|
309
|
+
fixed' = fixed,
|
|
310
|
+
value' = value,
|
|
311
|
+
prev' = prev,
|
|
312
|
+
collapsed' = collapsed,
|
|
313
|
+
justRestored' = false,
|
|
314
|
+
focus' = focus,
|
|
315
|
+
ariaNow' = ariaNow,
|
|
316
|
+
requests' = requests,
|
|
317
|
+
controlled' = controlled,
|
|
318
|
+
accepting' = accepting,
|
|
319
|
+
valueProp' = valueProp,
|
|
320
|
+
requested' = requested,
|
|
321
|
+
outcome' = outcome,
|
|
322
|
+
base' = base
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
action orientHorizontal = all {
|
|
326
|
+
orientation' = "horizontal",
|
|
327
|
+
fixed' = fixed,
|
|
328
|
+
value' = value,
|
|
329
|
+
prev' = prev,
|
|
330
|
+
collapsed' = collapsed,
|
|
331
|
+
justRestored' = false,
|
|
332
|
+
focus' = focus,
|
|
333
|
+
ariaNow' = ariaNow,
|
|
334
|
+
requests' = requests,
|
|
335
|
+
controlled' = controlled,
|
|
336
|
+
accepting' = accepting,
|
|
337
|
+
valueProp' = valueProp,
|
|
338
|
+
requested' = requested,
|
|
339
|
+
outcome' = outcome,
|
|
340
|
+
base' = base
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
action makeFixed = all {
|
|
344
|
+
orientation' = orientation,
|
|
345
|
+
fixed' = true,
|
|
346
|
+
value' = value,
|
|
347
|
+
prev' = prev,
|
|
348
|
+
collapsed' = collapsed,
|
|
349
|
+
justRestored' = false,
|
|
350
|
+
focus' = focus,
|
|
351
|
+
ariaNow' = ariaNow,
|
|
352
|
+
requests' = requests,
|
|
353
|
+
controlled' = controlled,
|
|
354
|
+
accepting' = accepting,
|
|
355
|
+
valueProp' = valueProp,
|
|
356
|
+
requested' = requested,
|
|
357
|
+
outcome' = outcome,
|
|
358
|
+
base' = base
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
action makeResizable = all {
|
|
362
|
+
orientation' = orientation,
|
|
363
|
+
fixed' = false,
|
|
364
|
+
value' = value,
|
|
365
|
+
prev' = prev,
|
|
366
|
+
collapsed' = collapsed,
|
|
367
|
+
justRestored' = false,
|
|
368
|
+
focus' = focus,
|
|
369
|
+
ariaNow' = ariaNow,
|
|
370
|
+
requests' = requests,
|
|
371
|
+
controlled' = controlled,
|
|
372
|
+
accepting' = accepting,
|
|
373
|
+
valueProp' = valueProp,
|
|
374
|
+
requested' = requested,
|
|
375
|
+
outcome' = outcome,
|
|
376
|
+
base' = base
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// commit: the host writes the controlled value (a no-op while uncontrolled).
|
|
380
|
+
// `collapsed` is kept consistent: a value other than MIN cannot be collapsed.
|
|
381
|
+
action setValue = {
|
|
382
|
+
nondet v = Set(0, 2, 4, 6).oneOf()
|
|
383
|
+
all {
|
|
384
|
+
orientation' = orientation,
|
|
385
|
+
fixed' = fixed,
|
|
386
|
+
value' = if (controlled) v else value,
|
|
387
|
+
prev' = if (controlled) (if (v == MIN) prev else v) else prev,
|
|
388
|
+
collapsed' = if (controlled) (if (v == MIN) collapsed else false) else collapsed,
|
|
389
|
+
justRestored' = if (controlled) false else justRestored,
|
|
390
|
+
focus' = focus,
|
|
391
|
+
ariaNow' = if (controlled) v else ariaNow,
|
|
392
|
+
requests' = requests,
|
|
393
|
+
controlled' = controlled,
|
|
394
|
+
accepting' = accepting,
|
|
395
|
+
valueProp' = if (controlled) v else valueProp,
|
|
396
|
+
requested' = requested,
|
|
397
|
+
outcome' = if (controlled) "none" else outcome,
|
|
398
|
+
base' = base
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// commit: the host flips its own copy of the value between MIN and MAX
|
|
403
|
+
action hostToggle = all {
|
|
404
|
+
orientation' = orientation,
|
|
405
|
+
fixed' = fixed,
|
|
406
|
+
value' = if (controlled) (if (valueProp == MAX) MIN else MAX) else value,
|
|
407
|
+
prev' = if (controlled) (if (valueProp == MAX) prev else valueProp) else prev,
|
|
408
|
+
collapsed' = if (controlled) (if (valueProp == MAX) collapsed else false) else collapsed,
|
|
409
|
+
justRestored' = if (controlled) false else justRestored,
|
|
410
|
+
focus' = focus,
|
|
411
|
+
ariaNow' = if (controlled) (if (valueProp == MAX) MIN else MAX) else ariaNow,
|
|
412
|
+
requests' = requests,
|
|
413
|
+
controlled' = controlled,
|
|
414
|
+
accepting' = accepting,
|
|
415
|
+
valueProp' = if (controlled) (if (valueProp == MAX) MIN else MAX) else valueProp,
|
|
416
|
+
requested' = requested,
|
|
417
|
+
outcome' = if (controlled) "none" else outcome,
|
|
418
|
+
base' = base
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// configuration: the host starts owning the value, adopting the current one
|
|
422
|
+
action control = all {
|
|
423
|
+
orientation' = orientation,
|
|
424
|
+
fixed' = fixed,
|
|
425
|
+
value' = value,
|
|
426
|
+
prev' = prev,
|
|
427
|
+
collapsed' = collapsed,
|
|
428
|
+
justRestored' = false,
|
|
429
|
+
focus' = focus,
|
|
430
|
+
ariaNow' = ariaNow,
|
|
431
|
+
requests' = requests,
|
|
432
|
+
controlled' = true,
|
|
433
|
+
accepting' = accepting,
|
|
434
|
+
valueProp' = value,
|
|
435
|
+
requested' = requested,
|
|
436
|
+
outcome' = outcome,
|
|
437
|
+
base' = base
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// configuration: the controlled host answers every request with its intent
|
|
441
|
+
action acceptRequests = all {
|
|
442
|
+
orientation' = orientation,
|
|
443
|
+
fixed' = fixed,
|
|
444
|
+
value' = value,
|
|
445
|
+
prev' = prev,
|
|
446
|
+
collapsed' = collapsed,
|
|
447
|
+
justRestored' = false,
|
|
448
|
+
focus' = focus,
|
|
449
|
+
ariaNow' = ariaNow,
|
|
450
|
+
requests' = requests,
|
|
451
|
+
controlled' = controlled,
|
|
452
|
+
accepting' = true,
|
|
453
|
+
valueProp' = valueProp,
|
|
454
|
+
requested' = requested,
|
|
455
|
+
outcome' = outcome,
|
|
456
|
+
base' = base
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
action step = any {
|
|
460
|
+
init, focusSplitter, blur, left, right, up, down, home, end, enter, f6,
|
|
461
|
+
orientVertical, orientHorizontal, makeFixed, makeResizable,
|
|
462
|
+
setValue, hostToggle, control, acceptRequests
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// APG: aria-valuenow stays within aria-valuemin..aria-valuemax
|
|
466
|
+
val ValueInRange: bool = and(value >= MIN, value <= MAX)
|
|
467
|
+
// the rendered aria-valuenow always mirrors the widget value
|
|
468
|
+
val AriaNowMirrorsValue: bool = ariaNow == value
|
|
469
|
+
// a collapsed primary pane sits at the minimum
|
|
470
|
+
val CollapsedAtMin: bool = or(not(collapsed), value == MIN)
|
|
471
|
+
// the remembered position is always a valid position
|
|
472
|
+
val PrevInRange: bool = and(prev >= MIN, prev <= MAX)
|
|
473
|
+
// restoring returns the splitter to exactly the remembered value
|
|
474
|
+
val RestoreReturnsPrev: bool = or(not(justRestored), and(value == prev, not(collapsed)))
|
|
475
|
+
// focus is one of the modelled positions
|
|
476
|
+
val FocusKnown: bool = or(focus == "none", or(focus == "splitter", or(focus == "primary", focus == "secondary")))
|
|
477
|
+
// orientation is one of the two APG orientations
|
|
478
|
+
val OrientationKnown: bool = ariaOrientationKnown(orientation)
|
|
479
|
+
// callbacks only ever count up from zero
|
|
480
|
+
val RequestsNonNegative: bool = requests >= 0
|
|
481
|
+
// controlled: only the value prop sets the state, so no event commits
|
|
482
|
+
val ControlledFollowsProp: bool = or(not(controlled), value == valueProp)
|
|
483
|
+
// a rejected request leaves the value as it found it
|
|
484
|
+
val RejectedRequestUntouched: bool = or(not(outcome == "rejected"), value == base)
|
|
485
|
+
// an accepted request committed exactly its target
|
|
486
|
+
val AcceptedRequestCommits: bool = or(not(outcome == "accepted"), value == requested)
|
|
487
|
+
}
|