@jxsuite/ui 0.0.0 → 0.1.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/components/jx-accordion-item.json +281 -0
- package/components/jx-accordion.json +33 -0
- package/components/jx-action-button.json +261 -33
- package/components/jx-action-group.json +123 -0
- package/components/jx-button.json +133 -25
- package/components/jx-checkbox.json +215 -0
- package/components/jx-color-area.json +263 -0
- package/components/jx-color-field.json +565 -0
- package/components/jx-color-slider.json +216 -0
- package/components/jx-combobox.json +544 -0
- package/components/jx-dialog.json +416 -0
- package/components/jx-divider.json +52 -0
- package/components/jx-dot.json +38 -0
- package/components/jx-field.json +162 -0
- package/components/jx-kbd.json +24 -0
- package/components/jx-listbox.json +76 -0
- package/components/jx-menu-item.json +5 -12
- package/components/jx-menu.json +45 -6
- package/components/jx-number-field.json +441 -0
- package/components/jx-option.json +350 -0
- package/components/jx-popover.json +227 -0
- package/components/jx-select.json +637 -0
- package/components/jx-spinner.json +129 -0
- package/components/jx-split.json +221 -0
- package/components/jx-swatch-group.json +107 -0
- package/components/jx-swatch.json +262 -0
- package/components/jx-switch.json +253 -0
- package/components/jx-tab-panel.json +58 -0
- package/components/jx-tab.json +296 -0
- package/components/jx-tabs.json +124 -0
- package/components/jx-textfield.json +639 -0
- package/components/jx-toast-host.json +121 -0
- package/components/jx-toast.json +255 -0
- package/components/jx-toolbar.json +81 -0
- package/components/jx-tooltip.json +207 -0
- package/components/jx-tree-item.json +325 -0
- package/components/jx-tree.json +202 -0
- package/icons/list.json +4 -0
- package/icons/manifest.json +12 -0
- package/package.json +27 -5
- package/project.json +164 -153
- package/src/behaviors/action-group.ts +255 -0
- package/src/behaviors/color-area.ts +303 -0
- package/src/behaviors/color-field.ts +465 -0
- package/src/behaviors/color-slider.ts +154 -0
- package/src/behaviors/combobox.ts +474 -0
- package/src/behaviors/dialog.ts +137 -0
- package/src/behaviors/listbox.ts +118 -0
- package/src/behaviors/menu.ts +80 -48
- package/src/behaviors/number-field.ts +161 -0
- package/src/behaviors/popover.ts +399 -0
- package/src/behaviors/select.ts +154 -0
- package/src/behaviors/split.ts +478 -0
- package/src/behaviors/swatch-group.ts +297 -0
- package/src/behaviors/tabs.ts +319 -0
- package/src/behaviors/textfield.ts +164 -0
- package/src/behaviors/toast-host.ts +241 -0
- package/src/behaviors/toast.ts +261 -0
- package/src/behaviors/toolbar.ts +413 -0
- package/src/behaviors/tooltip.ts +715 -0
- package/src/behaviors/tree.ts +830 -0
- package/src/color.ts +433 -0
- package/src/documents.ts +91 -1
- package/src/index.ts +41 -1
- package/src/loaders.ts +47 -0
- package/src/testing/anchor-support.ts +28 -0
- package/src/testing/popover-shim.ts +39 -6
- package/src/theme.ts +30 -6
- package/stylebook/jx-accordion-item.json +195 -0
- package/stylebook/jx-accordion.json +220 -0
- package/stylebook/jx-action-button.json +191 -23
- package/stylebook/jx-action-group.json +335 -0
- package/stylebook/jx-button.json +129 -26
- package/stylebook/jx-checkbox.json +245 -0
- package/stylebook/jx-color-area.json +272 -0
- package/stylebook/jx-color-field.json +261 -0
- package/stylebook/jx-color-slider.json +220 -0
- package/stylebook/jx-combobox.json +332 -0
- package/stylebook/jx-dialog.json +186 -0
- package/stylebook/jx-divider.json +125 -0
- package/stylebook/jx-dot.json +92 -0
- package/stylebook/jx-field.json +313 -0
- package/stylebook/jx-icon.json +4 -0
- package/stylebook/jx-kbd.json +90 -0
- package/stylebook/jx-listbox.json +337 -0
- package/stylebook/jx-menu.json +0 -1
- package/stylebook/jx-number-field.json +203 -0
- package/stylebook/jx-option.json +285 -0
- package/stylebook/jx-popover.json +123 -0
- package/stylebook/jx-select.json +407 -0
- package/stylebook/jx-spinner.json +111 -0
- package/stylebook/jx-split.json +170 -0
- package/stylebook/jx-swatch-group.json +175 -0
- package/stylebook/jx-swatch.json +249 -0
- package/stylebook/jx-switch.json +240 -0
- package/stylebook/jx-tab-panel.json +147 -0
- package/stylebook/jx-tab.json +201 -0
- package/stylebook/jx-tabs.json +278 -0
- package/stylebook/jx-textfield.json +309 -0
- package/stylebook/jx-toast-host.json +157 -0
- package/stylebook/jx-toast.json +266 -0
- package/stylebook/jx-toolbar.json +435 -0
- package/stylebook/jx-tooltip.json +162 -0
- package/stylebook/jx-tree-item.json +258 -0
- package/stylebook/jx-tree.json +429 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://jxsuite.com/schema/v1",
|
|
3
|
+
"$id": "JxToastHost",
|
|
4
|
+
"tagName": "jx-toast-host",
|
|
5
|
+
"observedAttributes": ["label", "live", "placement", "hotkey"],
|
|
6
|
+
"state": {
|
|
7
|
+
"label": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"default": "Notifications",
|
|
10
|
+
"attribute": "label",
|
|
11
|
+
"description": "The region's accessible name, so a reader who lands in it is told what it is rather than hearing a message with no provenance. It names the STACK and never a toast: the messages inside it change, and a region renamed on every arrival is a region announced on every arrival."
|
|
12
|
+
},
|
|
13
|
+
"live": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"default": "polite",
|
|
16
|
+
"attribute": "live",
|
|
17
|
+
"description": "polite, assertive or off: how the stack is announced. polite waits for a pause and is right for an outcome; assertive interrupts and is for the rare message that cannot wait. off is for a host that already says these things somewhere else — Jx Studio announces through its own single announcer, and a region here as well would say every notification twice. Role and attribute move together: polite writes role=status, assertive writes role=alert, off writes neither, so an assistive technology reading the role and one reading the attribute agree."
|
|
18
|
+
},
|
|
19
|
+
"placement": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"default": "bottom-end",
|
|
22
|
+
"attribute": "placement",
|
|
23
|
+
"description": "bottom-end, bottom-start, top-end or top-start: which corner the stack is pinned to. It moves the box and NOT the order — the toasts are drawn in the order they are written, whichever corner they are in, so the order a reader hears, the order they tab through and the order they see stay one order. A host that wants the stack in the flow of its own layout overrides position in its own stylesheet; nothing here depends on the fixed box."
|
|
24
|
+
},
|
|
25
|
+
"hotkey": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"default": "F8",
|
|
28
|
+
"attribute": "hotkey",
|
|
29
|
+
"description": "The key that moves focus to the first control in the stack. It is what makes a recovery control reachable at all: the stack is at the end of the document and a toast may expire before a reader could Tab to it, so the reader asks for it in one press instead — and arriving suspends every clock in the stack, so nothing then expires under their hand. Escape gives focus back to where it came from, and so does a toast closing while the reader is in it. A press carrying Ctrl, Alt or Meta is left alone. Empty turns the gesture off, for an application that owns a command of its own for this."
|
|
30
|
+
},
|
|
31
|
+
"onMount": {
|
|
32
|
+
"$prototype": "Function",
|
|
33
|
+
"$src": "jx-ui:/behaviors/toast-host.ts",
|
|
34
|
+
"$export": "onHostMount",
|
|
35
|
+
"description": "Registers the stack's key on the document. It has to be the document: a key that only worked once focus was already in the stack would answer the question it exists to answer with itself."
|
|
36
|
+
},
|
|
37
|
+
"onUnmount": {
|
|
38
|
+
"$prototype": "Function",
|
|
39
|
+
"$src": "jx-ui:/behaviors/toast-host.ts",
|
|
40
|
+
"$export": "onHostUnmount",
|
|
41
|
+
"description": "Takes the key back when the stack leaves the document, so a removed host cannot go on answering a press for a stack it can no longer show."
|
|
42
|
+
},
|
|
43
|
+
"onHold": {
|
|
44
|
+
"$prototype": "Function",
|
|
45
|
+
"$src": "jx-ui:/behaviors/toast-host.ts",
|
|
46
|
+
"$export": "onStackHold",
|
|
47
|
+
"description": "Pointer or focus arrived anywhere in the stack: every toast in it is told to suspend its clock, not only the one underneath. An older toast retiring while the reader answers a newer one would move the very control they were reaching for."
|
|
48
|
+
},
|
|
49
|
+
"onRelease": {
|
|
50
|
+
"$prototype": "Function",
|
|
51
|
+
"$src": "jx-ui:/behaviors/toast-host.ts",
|
|
52
|
+
"$export": "onStackRelease",
|
|
53
|
+
"description": "The pointer or the focus left the stack for something outside it, so the clocks run again. A move between two toasts of one stack is not a departure and releases nothing."
|
|
54
|
+
},
|
|
55
|
+
"onClose": {
|
|
56
|
+
"$prototype": "Function",
|
|
57
|
+
"$src": "jx-ui:/behaviors/toast-host.ts",
|
|
58
|
+
"$export": "onStackClose",
|
|
59
|
+
"description": "A toast closed. If it took the reader's focus with it, focus goes back to where the hotkey found it; if the reader was somewhere else entirely, nothing moves."
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"onpointerover": {
|
|
63
|
+
"$ref": "#/state/onHold"
|
|
64
|
+
},
|
|
65
|
+
"onpointerout": {
|
|
66
|
+
"$ref": "#/state/onRelease"
|
|
67
|
+
},
|
|
68
|
+
"onfocusin": {
|
|
69
|
+
"$ref": "#/state/onHold"
|
|
70
|
+
},
|
|
71
|
+
"onfocusout": {
|
|
72
|
+
"$ref": "#/state/onRelease"
|
|
73
|
+
},
|
|
74
|
+
"onclose": {
|
|
75
|
+
"$ref": "#/state/onClose"
|
|
76
|
+
},
|
|
77
|
+
"attributes": {
|
|
78
|
+
"role": "${state.live === 'off' ? null : state.live === 'assertive' ? 'alert' : 'status'}",
|
|
79
|
+
"aria-live": "${state.live}",
|
|
80
|
+
"aria-atomic": "false",
|
|
81
|
+
"aria-label": "${state.label || null}",
|
|
82
|
+
"data-placement": "${state.placement}"
|
|
83
|
+
},
|
|
84
|
+
"style": {
|
|
85
|
+
"$description": "aria-atomic is false and written out rather than left to the role, which supplies true: a stack re-read whole on every arrival would announce three old messages to deliver one new one. pointer-events is none on the box and auto on each toast, so the empty corner the stack reserves is not a hole the page cannot be clicked through.",
|
|
86
|
+
"display": "flex",
|
|
87
|
+
"flexDirection": "column",
|
|
88
|
+
"gap": "var(--jx-space-3)",
|
|
89
|
+
"position": "fixed",
|
|
90
|
+
"zIndex": "1000",
|
|
91
|
+
"insetBlockEnd": "var(--jx-space-4)",
|
|
92
|
+
"insetInlineEnd": "var(--jx-space-4)",
|
|
93
|
+
"alignItems": "flex-end",
|
|
94
|
+
"maxInlineSize": "min(420px, calc(100vw - 2 * var(--jx-space-4)))",
|
|
95
|
+
"pointerEvents": "none",
|
|
96
|
+
"&[hidden]": {
|
|
97
|
+
"display": "none"
|
|
98
|
+
},
|
|
99
|
+
"&[data-placement=\"top-end\"]": {
|
|
100
|
+
"insetBlockStart": "var(--jx-space-4)",
|
|
101
|
+
"insetBlockEnd": "auto"
|
|
102
|
+
},
|
|
103
|
+
"&[data-placement=\"bottom-start\"]": {
|
|
104
|
+
"insetInlineStart": "var(--jx-space-4)",
|
|
105
|
+
"insetInlineEnd": "auto",
|
|
106
|
+
"alignItems": "flex-start"
|
|
107
|
+
},
|
|
108
|
+
"&[data-placement=\"top-start\"]": {
|
|
109
|
+
"insetBlockStart": "var(--jx-space-4)",
|
|
110
|
+
"insetBlockEnd": "auto",
|
|
111
|
+
"insetInlineStart": "var(--jx-space-4)",
|
|
112
|
+
"insetInlineEnd": "auto",
|
|
113
|
+
"alignItems": "flex-start"
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"children": [
|
|
117
|
+
{
|
|
118
|
+
"tagName": "slot"
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://jxsuite.com/schema/v1",
|
|
3
|
+
"$id": "JxToast",
|
|
4
|
+
"tagName": "jx-toast",
|
|
5
|
+
"observedAttributes": ["variant", "open", "timeout", "dismiss-label"],
|
|
6
|
+
"$elements": [
|
|
7
|
+
{
|
|
8
|
+
"$ref": "./jx-icon.json"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"$ref": "./jx-action-button.json"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"state": {
|
|
15
|
+
"variant": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"default": "info",
|
|
18
|
+
"attribute": "variant",
|
|
19
|
+
"description": "info, positive, negative or warning: what kind of outcome this is. It picks the accent along the toast's leading edge AND the glyph beside the message, so the severity survives greyscale, a colour-blind reader and a forced-colours theme — colour alone would be a WCAG 1.4.1 failure. It is not announced: the glyph is decorative and the toast carries no role of its own, so what a screen reader hears is the message, which is why the message has to SAY what happened rather than lean on the colour to say it."
|
|
20
|
+
},
|
|
21
|
+
"open": {
|
|
22
|
+
"type": "boolean",
|
|
23
|
+
"default": false,
|
|
24
|
+
"attribute": "open",
|
|
25
|
+
"description": "Whether the toast is showing. It is the host's to write — a toast appended with no open attribute draws nothing, deliberately, so that arriving and appearing are two decisions rather than one — and the element writes it back to false when it retires itself. It is also what runs the clock: opening starts timeout, and closing stops it."
|
|
26
|
+
},
|
|
27
|
+
"timeout": {
|
|
28
|
+
"type": "number",
|
|
29
|
+
"default": 0,
|
|
30
|
+
"attribute": "timeout",
|
|
31
|
+
"description": "How long the toast rests before retiring itself, in milliseconds. 0 is sticky and is the DEFAULT, which is what makes the number safe as a number: a removed attribute coerces through Number() to 0 (ui.md §5.3), and here that lands on the reading a numeric prop can never spell otherwise — nothing disappears unless a host asked for it to. The clock is suspended while the pointer is on the toast, while focus is inside it, and while the stack it belongs to is being read, and resumes with what was LEFT, so a reader who reaches the recovery control cannot have it expire under their hand."
|
|
32
|
+
},
|
|
33
|
+
"dismissLabel": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"default": "Dismiss",
|
|
36
|
+
"attribute": "dismiss-label",
|
|
37
|
+
"description": "The name of the dismiss button, which is always drawn: a toast that can only be waited out is one a reader cannot get rid of, and a sticky one would then be permanent. Write what is being dismissed where a page raises several kinds (\"Dismiss notification\"), because the button is named by this alone — the message beside it is a consumer's slotted content and cannot be read into a name."
|
|
38
|
+
},
|
|
39
|
+
"icon": "${state.variant === 'positive' ? 'check' : state.variant === 'negative' ? 'warning-circle' : state.variant === 'warning' ? 'warning' : 'info'}",
|
|
40
|
+
"onMount": {
|
|
41
|
+
"$prototype": "Function",
|
|
42
|
+
"$src": "jx-ui:/behaviors/toast.ts",
|
|
43
|
+
"$export": "onToastMount",
|
|
44
|
+
"emits": [
|
|
45
|
+
{
|
|
46
|
+
"name": "close",
|
|
47
|
+
"description": "The toast closed itself; detail.reason is timeout when the clock ran out."
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"description": "Learns the element and starts the clock, then follows open through data-open for the rest of the toast's life."
|
|
51
|
+
},
|
|
52
|
+
"onUnmount": {
|
|
53
|
+
"$prototype": "Function",
|
|
54
|
+
"$src": "jx-ui:/behaviors/toast.ts",
|
|
55
|
+
"$export": "onToastUnmount",
|
|
56
|
+
"description": "Stops the clock when the toast leaves the document, so a toast the host has already taken away cannot retire itself afterwards."
|
|
57
|
+
},
|
|
58
|
+
"onHold": {
|
|
59
|
+
"$prototype": "Function",
|
|
60
|
+
"$src": "jx-ui:/behaviors/toast.ts",
|
|
61
|
+
"$export": "onToastHold",
|
|
62
|
+
"description": "The pointer arrived, focus arrived, or the stack said to wait: the clock is suspended with its remaining time kept. Three separate reasons, held together, because a pointer leaving a toast the reader has tabbed into must not restart a clock the focus is still holding."
|
|
63
|
+
},
|
|
64
|
+
"onRelease": {
|
|
65
|
+
"$prototype": "Function",
|
|
66
|
+
"$src": "jx-ui:/behaviors/toast.ts",
|
|
67
|
+
"$export": "onToastRelease",
|
|
68
|
+
"description": "The last of those reasons went away, so the clock runs again for what was left of it. A focusout whose focus landed on another control inside this same toast is not a departure and releases nothing."
|
|
69
|
+
},
|
|
70
|
+
"onDismiss": {
|
|
71
|
+
"$prototype": "Function",
|
|
72
|
+
"$src": "jx-ui:/behaviors/toast.ts",
|
|
73
|
+
"$export": "onToastDismiss",
|
|
74
|
+
"emits": [
|
|
75
|
+
{
|
|
76
|
+
"name": "close",
|
|
77
|
+
"description": "The reader dismissed the toast; detail.reason is dismissed."
|
|
78
|
+
}
|
|
79
|
+
],
|
|
80
|
+
"description": "The dismiss button closes the toast and says who closed it."
|
|
81
|
+
},
|
|
82
|
+
"onAction": {
|
|
83
|
+
"$prototype": "Function",
|
|
84
|
+
"$src": "jx-ui:/behaviors/toast.ts",
|
|
85
|
+
"$export": "onToastAction",
|
|
86
|
+
"emits": [
|
|
87
|
+
{
|
|
88
|
+
"name": "close",
|
|
89
|
+
"description": "The recovery control was used; detail.reason is action."
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
"description": "A click on the control slotted into action closes the toast, without stopping the click: the control is the target, so its own handler has already run and a host listening above the toast is entitled to hear it. An answer that has been given is not still being asked."
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"onpointerenter": {
|
|
96
|
+
"$ref": "#/state/onHold"
|
|
97
|
+
},
|
|
98
|
+
"onpointerleave": {
|
|
99
|
+
"$ref": "#/state/onRelease"
|
|
100
|
+
},
|
|
101
|
+
"onfocusin": {
|
|
102
|
+
"$ref": "#/state/onHold"
|
|
103
|
+
},
|
|
104
|
+
"onfocusout": {
|
|
105
|
+
"$ref": "#/state/onRelease"
|
|
106
|
+
},
|
|
107
|
+
"onjx-toast-pause": {
|
|
108
|
+
"$ref": "#/state/onHold"
|
|
109
|
+
},
|
|
110
|
+
"onjx-toast-resume": {
|
|
111
|
+
"$ref": "#/state/onRelease"
|
|
112
|
+
},
|
|
113
|
+
"attributes": {
|
|
114
|
+
"data-variant": "${state.variant}",
|
|
115
|
+
"data-open": "${state.open ? '' : null}"
|
|
116
|
+
},
|
|
117
|
+
"style": {
|
|
118
|
+
"$description": "The toast carries NO live region and no role of its own, which is the one decision in this block that is about sound rather than about pixels: jx-toast-host owns the region, and a role here would announce every toast twice in the one arrangement the kit exists to serve. A toast used without a host is drawn and not announced, and the answer to that is a host.",
|
|
119
|
+
"display": "none",
|
|
120
|
+
"boxSizing": "border-box",
|
|
121
|
+
"alignItems": "center",
|
|
122
|
+
"gap": "var(--jx-space-3)",
|
|
123
|
+
"maxInlineSize": "min(420px, calc(100vw - 2 * var(--jx-space-4)))",
|
|
124
|
+
"padding": "var(--jx-space-3)",
|
|
125
|
+
"border": "1px solid var(--jx-border)",
|
|
126
|
+
"borderInlineStartWidth": "3px",
|
|
127
|
+
"borderInlineStartColor": "var(--jx-toast-accent)",
|
|
128
|
+
"borderRadius": "var(--jx-radius-md)",
|
|
129
|
+
"background": "var(--jx-bg-overlay)",
|
|
130
|
+
"color": "var(--jx-fg)",
|
|
131
|
+
"boxShadow": "var(--jx-shadow-popover)",
|
|
132
|
+
"fontFamily": "var(--jx-font-sans)",
|
|
133
|
+
"fontSize": "var(--jx-text-sm)",
|
|
134
|
+
"lineHeight": "var(--jx-leading-sm)",
|
|
135
|
+
"textAlign": "start",
|
|
136
|
+
"pointerEvents": "auto",
|
|
137
|
+
"opacity": "0",
|
|
138
|
+
"translate": "0 var(--jx-space-3)",
|
|
139
|
+
"transition": "opacity var(--jx-dur-1) var(--jx-ease-out), translate var(--jx-dur-1) var(--jx-ease-out), display var(--jx-dur-1) allow-discrete",
|
|
140
|
+
"--jx-toast-accent": "var(--jx-accent)",
|
|
141
|
+
"&[data-variant=\"positive\"]": {
|
|
142
|
+
"--jx-toast-accent": "var(--jx-success)"
|
|
143
|
+
},
|
|
144
|
+
"&[data-variant=\"negative\"]": {
|
|
145
|
+
"--jx-toast-accent": "var(--jx-danger)"
|
|
146
|
+
},
|
|
147
|
+
"&[data-variant=\"warning\"]": {
|
|
148
|
+
"--jx-toast-accent": "var(--jx-warning)"
|
|
149
|
+
},
|
|
150
|
+
"&[data-open]": {
|
|
151
|
+
"display": "flex",
|
|
152
|
+
"opacity": "1",
|
|
153
|
+
"translate": "0 0"
|
|
154
|
+
},
|
|
155
|
+
"@starting-style": {
|
|
156
|
+
"&[data-open]": {
|
|
157
|
+
"opacity": "0",
|
|
158
|
+
"translate": "0 var(--jx-space-3)"
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
"&[hidden]": {
|
|
162
|
+
"$description": "AFTER the open rule, and only because of it: [data-jx][hidden] and [data-jx][data-open] weigh the same, so the later one wins and a hidden open toast would otherwise still be drawn. The UA's own [hidden] rule cannot settle it either, since the element's own display beats it at any specificity.",
|
|
163
|
+
"display": "none"
|
|
164
|
+
},
|
|
165
|
+
"& [part=\"icon\"]": {
|
|
166
|
+
"display": "inline-flex",
|
|
167
|
+
"flex": "none",
|
|
168
|
+
"alignSelf": "flex-start",
|
|
169
|
+
"color": "var(--jx-toast-accent)"
|
|
170
|
+
},
|
|
171
|
+
"& [part=\"message\"]": {
|
|
172
|
+
"flex": "1",
|
|
173
|
+
"minInlineSize": "0",
|
|
174
|
+
"overflowWrap": "anywhere"
|
|
175
|
+
},
|
|
176
|
+
"& [part=\"action-slot\"]": {
|
|
177
|
+
"display": "contents"
|
|
178
|
+
},
|
|
179
|
+
"& [part=\"dismiss\"]": {
|
|
180
|
+
"flex": "none",
|
|
181
|
+
"alignSelf": "flex-start"
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
"children": [
|
|
185
|
+
{
|
|
186
|
+
"tagName": "span",
|
|
187
|
+
"attributes": {
|
|
188
|
+
"part": "icon",
|
|
189
|
+
"aria-hidden": "true"
|
|
190
|
+
},
|
|
191
|
+
"children": [
|
|
192
|
+
{
|
|
193
|
+
"tagName": "jx-icon",
|
|
194
|
+
"attributes": {
|
|
195
|
+
"part": "glyph"
|
|
196
|
+
},
|
|
197
|
+
"$props": {
|
|
198
|
+
"name": {
|
|
199
|
+
"$ref": "#/state/icon"
|
|
200
|
+
},
|
|
201
|
+
"weight": "bold"
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"tagName": "div",
|
|
208
|
+
"attributes": {
|
|
209
|
+
"part": "message"
|
|
210
|
+
},
|
|
211
|
+
"children": [
|
|
212
|
+
{
|
|
213
|
+
"tagName": "slot"
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"tagName": "span",
|
|
219
|
+
"attributes": {
|
|
220
|
+
"part": "action-slot",
|
|
221
|
+
"role": "none"
|
|
222
|
+
},
|
|
223
|
+
"onclick": {
|
|
224
|
+
"$ref": "#/state/onAction"
|
|
225
|
+
},
|
|
226
|
+
"children": [
|
|
227
|
+
{
|
|
228
|
+
"tagName": "slot",
|
|
229
|
+
"attributes": {
|
|
230
|
+
"name": "action"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
]
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"tagName": "jx-action-button",
|
|
237
|
+
"attributes": {
|
|
238
|
+
"part": "dismiss"
|
|
239
|
+
},
|
|
240
|
+
"$props": {
|
|
241
|
+
"icon": "x",
|
|
242
|
+
"size": "sm",
|
|
243
|
+
"label": {
|
|
244
|
+
"$ref": "#/state/dismissLabel"
|
|
245
|
+
},
|
|
246
|
+
"hint": {
|
|
247
|
+
"$ref": "#/state/dismissLabel"
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
"onclick": {
|
|
251
|
+
"$ref": "#/state/onDismiss"
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://jxsuite.com/schema/v1",
|
|
3
|
+
"$id": "JxToolbar",
|
|
4
|
+
"tagName": "jx-toolbar",
|
|
5
|
+
"observedAttributes": ["label", "orientation"],
|
|
6
|
+
"state": {
|
|
7
|
+
"label": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"default": "",
|
|
10
|
+
"attribute": "label",
|
|
11
|
+
"description": "The accessible name of the toolbar, and it is not optional in practice: a toolbar is a container a reader is told they have entered, and an unnamed one is announced by its role alone. toolbar is in neither of the accessibility lint's named-role sets, so nothing lints its absence — the element's own test pins it instead, and so does every surface that mounts one."
|
|
12
|
+
},
|
|
13
|
+
"orientation": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"default": "horizontal",
|
|
16
|
+
"attribute": "orientation",
|
|
17
|
+
"description": "horizontal or vertical. It chooses which arrow pair moves the caret between controls, and it turns the row through 90 degrees off aria-orientation — which role=toolbar both supports and defaults to horizontal, so unlike jx-action-group there is no second data- attribute to key the layout on."
|
|
18
|
+
},
|
|
19
|
+
"onKeydown": {
|
|
20
|
+
"$prototype": "Function",
|
|
21
|
+
"$src": "jx-ui:/behaviors/toolbar.ts",
|
|
22
|
+
"$export": "onToolbarKeydown",
|
|
23
|
+
"description": "The toolbar keyboard contract: the arrow pair of its own axis moves the roving caret between reachable controls with wrap, Home and End go to the ends, and a control that answers the key itself keeps it — a text field holds the arrows while its caret has text left to walk in that direction, and holds Home and End always."
|
|
24
|
+
},
|
|
25
|
+
"onReady": {
|
|
26
|
+
"$prototype": "Function",
|
|
27
|
+
"$src": "jx-ui:/behaviors/toolbar.ts",
|
|
28
|
+
"$export": "onToolbarReady",
|
|
29
|
+
"description": "Collapses the toolbar to one tab stop once it has rendered, and keeps it collapsed to one as controls come and go. It listens for the element's own jx-ready because onMount is handed the reactive scope alone, and placing a caret needs the host."
|
|
30
|
+
},
|
|
31
|
+
"onMount": {
|
|
32
|
+
"$prototype": "Function",
|
|
33
|
+
"body": [
|
|
34
|
+
{
|
|
35
|
+
"dispatchEvent": "jx-ready",
|
|
36
|
+
"bubbles": true
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"emits": [
|
|
40
|
+
{
|
|
41
|
+
"name": "jx-ready",
|
|
42
|
+
"description": "The toolbar has rendered and distributed its children, so its caret can be placed."
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"description": "Announces that the element has rendered. The toolbar's own onReady listens for it, and a host may too."
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"attributes": {
|
|
49
|
+
"role": "toolbar",
|
|
50
|
+
"aria-label": "${state.label || null}",
|
|
51
|
+
"aria-orientation": "${state.orientation}"
|
|
52
|
+
},
|
|
53
|
+
"onkeydown": {
|
|
54
|
+
"$ref": "#/state/onKeydown"
|
|
55
|
+
},
|
|
56
|
+
"onjx-ready": {
|
|
57
|
+
"$ref": "#/state/onReady"
|
|
58
|
+
},
|
|
59
|
+
"style": {
|
|
60
|
+
"display": "flex",
|
|
61
|
+
"&[hidden]": {
|
|
62
|
+
"display": "none"
|
|
63
|
+
},
|
|
64
|
+
"boxSizing": "border-box",
|
|
65
|
+
"alignItems": "center",
|
|
66
|
+
"gap": "var(--jx-space-2)",
|
|
67
|
+
"minWidth": "0",
|
|
68
|
+
"fontFamily": "var(--jx-font-sans)",
|
|
69
|
+
"fontSize": "var(--jx-text-md)",
|
|
70
|
+
"color": "var(--jx-fg)",
|
|
71
|
+
"&[aria-orientation=\"vertical\"]": {
|
|
72
|
+
"flexDirection": "column",
|
|
73
|
+
"alignItems": "stretch"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"children": [
|
|
77
|
+
{
|
|
78
|
+
"tagName": "slot"
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://jxsuite.com/schema/v1",
|
|
3
|
+
"$id": "JxTooltip",
|
|
4
|
+
"tagName": "jx-tooltip",
|
|
5
|
+
"observedAttributes": ["delay", "for", "placement", "x", "y", "arrow"],
|
|
6
|
+
"state": {
|
|
7
|
+
"delay": {
|
|
8
|
+
"type": "number",
|
|
9
|
+
"default": 500,
|
|
10
|
+
"attribute": "delay",
|
|
11
|
+
"description": "How long the pointer must rest on the control before the tip appears, in milliseconds. Keyboard focus never waits: a reader who tabbed to the control has already committed. Read only on the FALLBACK path — where the engine implements interest invokers and the control carries interestfor, the wait is the platform's own interest-delay-start and this number is not consulted, so set the CSS property on the control if you need to change it there."
|
|
12
|
+
},
|
|
13
|
+
"for": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"default": "",
|
|
16
|
+
"attribute": "for",
|
|
17
|
+
"description": "The id of the control this tip describes, in the same root. The declarative wiring is the other way round and is preferred — interestfor on the control, naming this tip's id, and this prop left unset — and it works on every engine: where interest invokers are missing the tip binds an interestfor control's pointer and focus events itself, exactly as it does for a control this prop names. Either way the listeners come off again when the tip leaves the document. It is read once, at mount; a host that wires a tip up later calls bindTooltip from jx-ui:/behaviors/tooltip.ts itself."
|
|
18
|
+
},
|
|
19
|
+
"placement": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"default": "block-end span-inline-end",
|
|
22
|
+
"attribute": "placement",
|
|
23
|
+
"description": "Where the tip sits relative to its control, as a CSS position-area value: below it with leading edges aligned by default, which is where the arrow points from. It applies while the tip is anchored — shown from a control the platform knows, by interestfor or by the element's own binding — on an engine with CSS anchor positioning; the platform then follows the control through scroll and resize and flips the tip above it when it would overflow (the --jx-tooltip-above try option, which keeps the gap on the right side). Elsewhere the tip stands at x and y, placed and flipped by the element itself."
|
|
24
|
+
},
|
|
25
|
+
"x": {
|
|
26
|
+
"type": "number",
|
|
27
|
+
"default": 0,
|
|
28
|
+
"attribute": "x",
|
|
29
|
+
"description": "Where the tip's inline-start edge sits, in viewport pixels, whenever the tip is NOT anchored: on an engine without CSS anchor positioning, or shown from nothing. Written by the element when it opens, from the box of the control it describes; a host that places the tip itself sets it and names no control."
|
|
30
|
+
},
|
|
31
|
+
"y": {
|
|
32
|
+
"type": "number",
|
|
33
|
+
"default": 0,
|
|
34
|
+
"attribute": "y",
|
|
35
|
+
"description": "Where the tip's block-start edge sits, in viewport pixels. The tip is placed under its control, or above it when there is no room below — never over it, because a tip that covers the control it describes hides what the reader is pointing at."
|
|
36
|
+
},
|
|
37
|
+
"arrow": {
|
|
38
|
+
"type": "boolean",
|
|
39
|
+
"default": false,
|
|
40
|
+
"attribute": "arrow",
|
|
41
|
+
"description": "Draws a pointer at the edge of the tip that faces its control — the block-start edge for a tip below it, the block-end edge for one that flipped above. Decorative, and aria-hidden: it says nothing the tip's own text does not."
|
|
42
|
+
},
|
|
43
|
+
"flipped": {
|
|
44
|
+
"type": "boolean",
|
|
45
|
+
"default": false,
|
|
46
|
+
"description": "Whether the tip landed ABOVE its control because there was no room below. Written by the element when it opens, and read by nothing but the arrow: a pointer pinned to the block-start edge of a tip that flipped points away from the control it belongs to. A host that places the tip itself sets x and y, and sets this to say which way its arrow faces. Anchored, the flip is the platform's and this is MEASURED — the tip's box above its control's — a frame after the tip shows and again, at most once per frame, whenever the page scrolls, the window resizes or either box changes size, until the tip closes, so the arrow follows a flip the element did not make, including one the platform makes while the tip is up."
|
|
47
|
+
},
|
|
48
|
+
"anchored": {
|
|
49
|
+
"type": "boolean",
|
|
50
|
+
"default": false,
|
|
51
|
+
"description": "Whether the platform is placing the tip against the control it was shown from. Written by the behaviour on beforetoggle, before layout, so the first frame is already in place; cleared on close; mirrored as data-anchored for the anchored rule. Not an attribute, because it is the platform's fact."
|
|
52
|
+
},
|
|
53
|
+
"open": {
|
|
54
|
+
"type": "boolean",
|
|
55
|
+
"default": false,
|
|
56
|
+
"description": "Whether the tip is showing. Follows the platform's toggle event; write it through showPopover() and hidePopover(), not directly."
|
|
57
|
+
},
|
|
58
|
+
"noArrow": {
|
|
59
|
+
"$expression": {
|
|
60
|
+
"operator": "!",
|
|
61
|
+
"target": {
|
|
62
|
+
"$ref": "#/state/arrow"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"onBeforeToggle": {
|
|
67
|
+
"$prototype": "Function",
|
|
68
|
+
"$src": "jx-ui:/behaviors/tooltip.ts",
|
|
69
|
+
"$export": "onTooltipBeforeToggle",
|
|
70
|
+
"description": "Decides anchored before the tip is laid out: an opening shown from a control the platform or the binding names is anchored; a closing clears it. Before layout, so a tip that learned it was anchored a frame late would not paint once at its coordinates and jump."
|
|
71
|
+
},
|
|
72
|
+
"onToggle": {
|
|
73
|
+
"$prototype": "Function",
|
|
74
|
+
"$src": "jx-ui:/behaviors/tooltip.ts",
|
|
75
|
+
"$export": "onTooltipToggle",
|
|
76
|
+
"description": "Mirrors the platform's toggle into open, and places a freshly shown tip under the control it describes — or, when the platform is placing it by anchor, only reads back which side of the control it is on — a frame later and then on every scroll, resize and size change while it shows — so the arrow can follow; the closing toggle stops that reading. Placing here rather than on the gesture is what lets the declarative path work: an interestfor control shows the tip without telling the element anything, and the toggle is the first the element hears of it."
|
|
77
|
+
},
|
|
78
|
+
"onReady": {
|
|
79
|
+
"$prototype": "Function",
|
|
80
|
+
"$src": "jx-ui:/behaviors/tooltip.ts",
|
|
81
|
+
"$export": "onTooltipReady",
|
|
82
|
+
"description": "Binds the control the tip is wired to — the one for names, or the one declaring interestfor at this tip — on the fallback path. Nothing is bound where the engine implements interest invokers and the control declares one, because there the platform owns the pair."
|
|
83
|
+
},
|
|
84
|
+
"onUnmount": {
|
|
85
|
+
"$prototype": "Function",
|
|
86
|
+
"$src": "jx-ui:/behaviors/tooltip.ts",
|
|
87
|
+
"$export": "onTooltipUnmount",
|
|
88
|
+
"description": "Takes the fallback listeners off the control again, one microtask after the tip left the document and only if it is still out by then. They sit on an element the kit does not own and which outlives the tip, so without this a removed tip keeps answering its control's pointer; but a tip that is MOVED, by a keyed $map reordering its rows or a host re-parenting the control, is disconnected and reconnected in one step and never mounts again, so an unmount that disposed at once would leave it silent for good."
|
|
89
|
+
},
|
|
90
|
+
"onMount": {
|
|
91
|
+
"$prototype": "Function",
|
|
92
|
+
"body": [
|
|
93
|
+
{
|
|
94
|
+
"dispatchEvent": "jx-ready",
|
|
95
|
+
"bubbles": true
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"description": "Announces that the element has rendered and carries its popover attribute, so a host may show it — and gives the element its own first sight of itself, which is how onReady reaches the control that for names."
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"onbeforetoggle": {
|
|
102
|
+
"$ref": "#/state/onBeforeToggle"
|
|
103
|
+
},
|
|
104
|
+
"ontoggle": {
|
|
105
|
+
"$ref": "#/state/onToggle"
|
|
106
|
+
},
|
|
107
|
+
"onjx-ready": {
|
|
108
|
+
"$ref": "#/state/onReady"
|
|
109
|
+
},
|
|
110
|
+
"attributes": {
|
|
111
|
+
"role": "tooltip",
|
|
112
|
+
"popover": "hint",
|
|
113
|
+
"data-open": "${state.open ? '' : null}",
|
|
114
|
+
"data-flipped": "${state.flipped ? '' : null}",
|
|
115
|
+
"data-anchored": "${state.anchored ? '' : null}"
|
|
116
|
+
},
|
|
117
|
+
"style": {
|
|
118
|
+
"display": "revert-layer",
|
|
119
|
+
"&[hidden]": {
|
|
120
|
+
"display": "none"
|
|
121
|
+
},
|
|
122
|
+
"position": "fixed",
|
|
123
|
+
"insetInlineStart": "${state.x}px",
|
|
124
|
+
"insetBlockStart": "${state.y}px",
|
|
125
|
+
"insetInlineEnd": "auto",
|
|
126
|
+
"insetBlockEnd": "auto",
|
|
127
|
+
"boxSizing": "border-box",
|
|
128
|
+
"margin": "0",
|
|
129
|
+
"padding": "var(--jx-space-1) var(--jx-space-3)",
|
|
130
|
+
"maxWidth": "min(280px, calc(100vw - 8px))",
|
|
131
|
+
"background": "var(--jx-bg-overlay)",
|
|
132
|
+
"color": "var(--jx-fg)",
|
|
133
|
+
"border": "1px solid var(--jx-border-strong)",
|
|
134
|
+
"borderRadius": "var(--jx-radius-sm)",
|
|
135
|
+
"boxShadow": "var(--jx-shadow-popover)",
|
|
136
|
+
"fontFamily": "var(--jx-font-sans)",
|
|
137
|
+
"fontSize": "var(--jx-text-sm)",
|
|
138
|
+
"lineHeight": "var(--jx-leading-sm)",
|
|
139
|
+
"textAlign": "start",
|
|
140
|
+
"opacity": "1",
|
|
141
|
+
"pointerEvents": "auto",
|
|
142
|
+
"transition": "opacity var(--jx-dur-1) var(--jx-ease-out), display var(--jx-dur-1) allow-discrete, overlay var(--jx-dur-1) allow-discrete",
|
|
143
|
+
":popover-open": {
|
|
144
|
+
"display": "block"
|
|
145
|
+
},
|
|
146
|
+
"&[hidden]:popover-open": {
|
|
147
|
+
"display": "none"
|
|
148
|
+
},
|
|
149
|
+
"@position-try --jx-tooltip-above": {
|
|
150
|
+
"positionArea": "block-start span-inline-end",
|
|
151
|
+
"marginBlockStart": "0",
|
|
152
|
+
"marginBlockEnd": "6px"
|
|
153
|
+
},
|
|
154
|
+
"@supports (position-area: block-end)": {
|
|
155
|
+
"$description": "The anchored placement: the platform puts the tip against its IMPLICIT anchor — the control it was shown from, by interestfor or by the binding's showPopover({ source }) — follows that control through scroll and resize, and flips the tip above it when it would overflow, through the --jx-tooltip-above try option rather than a bare flip-block so the 6px gap the arrow fills moves to the other side with it. No anchor-name is involved (ui.md 5.2, 6). The insets are released so x and y stop mattering. Outside this block the coordinate placement above is the answer, unchanged.",
|
|
156
|
+
"&[data-anchored]": {
|
|
157
|
+
"insetInlineStart": "auto",
|
|
158
|
+
"insetBlockStart": "auto",
|
|
159
|
+
"marginBlockStart": "6px",
|
|
160
|
+
"positionArea": "${state.placement}",
|
|
161
|
+
"positionTryFallbacks": "--jx-tooltip-above, flip-inline, --jx-tooltip-above flip-inline"
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"@starting-style": {
|
|
165
|
+
"&:popover-open": {
|
|
166
|
+
"opacity": "0"
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"& > [part=\"arrow\"]": {
|
|
170
|
+
"position": "absolute",
|
|
171
|
+
"insetBlockEnd": "100%",
|
|
172
|
+
"insetInlineStart": "var(--jx-space-4)",
|
|
173
|
+
"width": "8px",
|
|
174
|
+
"height": "8px",
|
|
175
|
+
"marginBlockEnd": "-5px",
|
|
176
|
+
"background": "var(--jx-bg-overlay)",
|
|
177
|
+
"borderInlineStart": "1px solid var(--jx-border-strong)",
|
|
178
|
+
"borderBlockStart": "1px solid var(--jx-border-strong)",
|
|
179
|
+
"transform": "rotate(45deg)"
|
|
180
|
+
},
|
|
181
|
+
"&[data-flipped] > [part=\"arrow\"]": {
|
|
182
|
+
"insetBlockEnd": "auto",
|
|
183
|
+
"insetBlockStart": "100%",
|
|
184
|
+
"marginBlockEnd": "0",
|
|
185
|
+
"marginBlockStart": "-5px",
|
|
186
|
+
"borderInlineStart": "none",
|
|
187
|
+
"borderBlockStart": "none",
|
|
188
|
+
"borderInlineEnd": "1px solid var(--jx-border-strong)",
|
|
189
|
+
"borderBlockEnd": "1px solid var(--jx-border-strong)"
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"children": [
|
|
193
|
+
{
|
|
194
|
+
"tagName": "slot"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"tagName": "div",
|
|
198
|
+
"attributes": {
|
|
199
|
+
"part": "arrow",
|
|
200
|
+
"aria-hidden": "true"
|
|
201
|
+
},
|
|
202
|
+
"hidden": {
|
|
203
|
+
"$ref": "#/state/noArrow"
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
}
|