@rip-lang/ui 0.3.67 → 0.4.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/AGENTS.md +93 -0
- package/README.md +22 -625
- package/browser/AGENTS.md +213 -0
- package/browser/CONTRIBUTING.md +375 -0
- package/browser/README.md +11 -0
- package/browser/TESTING.md +59 -0
- package/browser/browser.rip +56 -0
- package/{components → browser/components}/accordion.rip +1 -1
- package/{components → browser/components}/alert-dialog.rip +6 -3
- package/{components → browser/components}/autocomplete.rip +27 -21
- package/{components → browser/components}/avatar.rip +3 -3
- package/{components → browser/components}/badge.rip +1 -1
- package/{components → browser/components}/breadcrumb.rip +2 -2
- package/{components → browser/components}/button-group.rip +3 -3
- package/{components → browser/components}/button.rip +2 -2
- package/{components → browser/components}/card.rip +1 -1
- package/{components → browser/components}/carousel.rip +5 -5
- package/{components → browser/components}/checkbox-group.rip +40 -11
- package/{components → browser/components}/checkbox.rip +4 -4
- package/{components → browser/components}/collapsible.rip +2 -2
- package/{components → browser/components}/combobox.rip +36 -23
- package/{components → browser/components}/context-menu.rip +1 -1
- package/{components → browser/components}/date-picker.rip +5 -5
- package/{components → browser/components}/dialog.rip +8 -4
- package/{components → browser/components}/drawer.rip +8 -4
- package/{components → browser/components}/editable-value.rip +7 -1
- package/{components → browser/components}/field.rip +5 -5
- package/{components → browser/components}/fieldset.rip +2 -2
- package/{components → browser/components}/form.rip +1 -1
- package/{components → browser/components}/grid.rip +8 -8
- package/{components → browser/components}/input-group.rip +1 -1
- package/{components → browser/components}/input.rip +6 -6
- package/{components → browser/components}/label.rip +2 -2
- package/{components → browser/components}/menu.rip +17 -10
- package/{components → browser/components}/menubar.rip +1 -1
- package/{components → browser/components}/meter.rip +7 -7
- package/{components → browser/components}/multi-select.rip +76 -33
- package/{components → browser/components}/native-select.rip +3 -3
- package/{components → browser/components}/nav-menu.rip +3 -3
- package/{components → browser/components}/number-field.rip +11 -11
- package/{components → browser/components}/otp-field.rip +4 -4
- package/{components → browser/components}/pagination.rip +4 -4
- package/{components → browser/components}/popover.rip +11 -24
- package/{components → browser/components}/preview-card.rip +7 -11
- package/{components → browser/components}/progress.rip +3 -3
- package/{components → browser/components}/radio-group.rip +4 -4
- package/{components → browser/components}/resizable.rip +3 -3
- package/{components → browser/components}/scroll-area.rip +1 -1
- package/{components → browser/components}/select.rip +55 -27
- package/{components → browser/components}/separator.rip +2 -2
- package/{components → browser/components}/skeleton.rip +4 -4
- package/{components → browser/components}/slider.rip +15 -10
- package/{components → browser/components}/spinner.rip +2 -2
- package/{components → browser/components}/table.rip +2 -2
- package/{components → browser/components}/tabs.rip +12 -7
- package/{components → browser/components}/textarea.rip +8 -8
- package/{components → browser/components}/toast.rip +3 -3
- package/{components → browser/components}/toggle-group.rip +42 -11
- package/{components → browser/components}/toggle.rip +2 -2
- package/{components → browser/components}/toolbar.rip +2 -2
- package/{components → browser/components}/tooltip.rip +19 -23
- package/browser/hljs-rip.js +209 -0
- package/browser/playwright.config.mjs +31 -0
- package/browser/tests/overlays.js +352 -0
- package/email/AGENTS.md +16 -0
- package/email/README.md +55 -0
- package/email/benchmarks/benchmark.rip +94 -0
- package/email/benchmarks/samples.rip +104 -0
- package/email/compat.rip +129 -0
- package/email/components.rip +371 -0
- package/email/dom.rip +330 -0
- package/email/email.rip +10 -0
- package/email/render.rip +82 -0
- package/package.json +29 -39
- package/shared/README.md +3 -0
- package/shared/styles.rip +17 -0
- package/tailwind/AGENTS.md +3 -0
- package/tailwind/README.md +27 -0
- package/tailwind/engine.js +107 -0
- package/tailwind/inline.js +215 -0
- package/tailwind/serve.js +6 -0
- package/tailwind/tailwind.rip +13 -0
- package/ui.rip +3 -0
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
|
|
22
22
|
export Grid = component
|
|
23
23
|
|
|
24
|
-
@data
|
|
25
|
-
@columns
|
|
26
|
-
@rowHeight
|
|
27
|
-
@headerHeight := 36
|
|
28
|
-
@overscan
|
|
29
|
-
@striped
|
|
30
|
-
@beforeEdit := null
|
|
31
|
-
@afterEdit
|
|
24
|
+
@data:: any[] := []
|
|
25
|
+
@columns:: any[] := []
|
|
26
|
+
@rowHeight:: number := 32
|
|
27
|
+
@headerHeight:: number := 36
|
|
28
|
+
@overscan:: number := 5
|
|
29
|
+
@striped:: boolean := false
|
|
30
|
+
@beforeEdit:: any := null
|
|
31
|
+
@afterEdit:: any := null
|
|
32
32
|
|
|
33
33
|
formatRegistry = []
|
|
34
34
|
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
# Input value <=> name, placeholder: "Enter name"
|
|
8
8
|
# Input value <=> email, type: "email", required: true
|
|
9
9
|
|
|
10
|
-
export Input = component
|
|
11
|
-
@value :=
|
|
12
|
-
@placeholder :=
|
|
13
|
-
@type :=
|
|
14
|
-
@disabled := false
|
|
15
|
-
@required := false
|
|
10
|
+
export Input = component extends input
|
|
11
|
+
@value:: string := ""
|
|
12
|
+
@placeholder:: string := ""
|
|
13
|
+
@type:: string := "text"
|
|
14
|
+
@disabled:: boolean := false
|
|
15
|
+
@required:: boolean := false
|
|
16
16
|
|
|
17
17
|
focused := false
|
|
18
18
|
touched := false
|
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
# div $item: "archive", "Archive"
|
|
13
13
|
|
|
14
14
|
export Menu = component
|
|
15
|
-
@disabled := false
|
|
15
|
+
@disabled:: boolean := false
|
|
16
16
|
|
|
17
17
|
open := false
|
|
18
18
|
highlightedIndex := -1
|
|
19
19
|
typeaheadBuffer := ''
|
|
20
20
|
typeaheadTimer := null
|
|
21
|
+
_ready := false
|
|
21
22
|
_id =! "menu-#{Math.random().toString(36).slice(2, 8)}"
|
|
22
23
|
|
|
23
24
|
items ~=
|
|
@@ -73,14 +74,10 @@ export Menu = component
|
|
|
73
74
|
@_list?.querySelectorAll('[role="menuitem"]')[idx]?.focus()
|
|
74
75
|
|
|
75
76
|
_applyPlacement: ->
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
@_list.style.positionArea = 'bottom start'
|
|
81
|
-
@_list.style.positionTry = 'flip-block, flip-inline, flip-block flip-inline'
|
|
82
|
-
@_list.style.positionVisibility = 'anchors-visible'
|
|
83
|
-
@_list.style.marginTop = '4px'
|
|
77
|
+
ARIA.position @_trigger, @_list, placement: 'bottom start', offset: 4
|
|
78
|
+
|
|
79
|
+
mounted: ->
|
|
80
|
+
_ready = true
|
|
84
81
|
|
|
85
82
|
onTriggerKeydown: (e) ->
|
|
86
83
|
return if @disabled
|
|
@@ -106,6 +103,7 @@ export Menu = component
|
|
|
106
103
|
char: => @_typeahead(e.key)
|
|
107
104
|
|
|
108
105
|
~>
|
|
106
|
+
return unless _ready
|
|
109
107
|
if @_list
|
|
110
108
|
@_list.id = _id
|
|
111
109
|
@_list.setAttribute 'popover', 'auto'
|
|
@@ -119,6 +117,7 @@ export Menu = component
|
|
|
119
117
|
button ref: "_trigger"
|
|
120
118
|
aria-haspopup: "menu"
|
|
121
119
|
aria-expanded: !!open
|
|
120
|
+
aria-controls: _id
|
|
122
121
|
$open: open?!
|
|
123
122
|
$disabled: @disabled?!
|
|
124
123
|
disabled: @disabled
|
|
@@ -129,7 +128,15 @@ export Menu = component
|
|
|
129
128
|
. ref: "_slot", style: "display:none"
|
|
130
129
|
slot
|
|
131
130
|
|
|
132
|
-
div ref: "_list"
|
|
131
|
+
div ref: "_list"
|
|
132
|
+
id: _id
|
|
133
|
+
role: "menu"
|
|
134
|
+
popover: "auto"
|
|
135
|
+
hidden: not open
|
|
136
|
+
aria-hidden: (open ? undefined : "true")
|
|
137
|
+
$open: open?!
|
|
138
|
+
style: "position:fixed;margin:0;inset:auto"
|
|
139
|
+
@keydown: @onMenuKeydown
|
|
133
140
|
for item, idx in items
|
|
134
141
|
div role: item.getAttribute('role') or 'menuitem'
|
|
135
142
|
tabindex: "-1"
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
# Meter value: 75, min: 0, max: 100
|
|
10
10
|
|
|
11
11
|
export Meter = component
|
|
12
|
-
@value := 0
|
|
13
|
-
@min := 0
|
|
14
|
-
@max := 1
|
|
15
|
-
@low := null
|
|
16
|
-
@high := null
|
|
17
|
-
@optimum := null
|
|
18
|
-
@label := null
|
|
12
|
+
@value:: number := 0
|
|
13
|
+
@min:: number := 0
|
|
14
|
+
@max:: number := 1
|
|
15
|
+
@low:: any := null
|
|
16
|
+
@high:: any := null
|
|
17
|
+
@optimum:: any := null
|
|
18
|
+
@label:: any := null
|
|
19
19
|
|
|
20
20
|
percent ~= Math.min(100, Math.max(0, ((@value - @min) / (@max - @min)) * 100))
|
|
21
21
|
|
|
@@ -8,14 +8,17 @@
|
|
|
8
8
|
# MultiSelect value <=> selectedColors, items: colors, placeholder: "Choose colors..."
|
|
9
9
|
|
|
10
10
|
export MultiSelect = component
|
|
11
|
-
@value := []
|
|
12
|
-
@items := []
|
|
13
|
-
@placeholder :=
|
|
14
|
-
@disabled := false
|
|
11
|
+
@value:: any[] := []
|
|
12
|
+
@items:: any[] := []
|
|
13
|
+
@placeholder:: string := "Select..."
|
|
14
|
+
@disabled:: boolean := false
|
|
15
15
|
|
|
16
16
|
open := false
|
|
17
17
|
query := ''
|
|
18
18
|
highlightedIndex := -1
|
|
19
|
+
_ready := false
|
|
20
|
+
_ignoreInputClickOnce := false
|
|
21
|
+
_popupGuard =! ARIA.popupGuard()
|
|
19
22
|
_listId =! "ms-#{Math.random().toString(36).slice(2, 8)}"
|
|
20
23
|
|
|
21
24
|
filtered ~=
|
|
@@ -25,6 +28,14 @@ export MultiSelect = component
|
|
|
25
28
|
label = if typeof item is 'string' then item else (item.label or item.name or String(item))
|
|
26
29
|
label.toLowerCase().includes(q)
|
|
27
30
|
|
|
31
|
+
# Block reopen briefly so the same pointer gesture that closed the popup
|
|
32
|
+
# cannot immediately reopen it via focus/click side effects.
|
|
33
|
+
_blockOpenBriefly: ->
|
|
34
|
+
_popupGuard.block()
|
|
35
|
+
|
|
36
|
+
_canOpen: ->
|
|
37
|
+
_popupGuard.canOpen()
|
|
38
|
+
|
|
28
39
|
_label: (item) ->
|
|
29
40
|
if typeof item is 'string' then item else (item.label or item.name or String(item))
|
|
30
41
|
|
|
@@ -45,47 +56,73 @@ export MultiSelect = component
|
|
|
45
56
|
arr.push v
|
|
46
57
|
@value = arr
|
|
47
58
|
@emit 'change', @value
|
|
59
|
+
@_close(true, true)
|
|
48
60
|
|
|
49
61
|
_removeChip: (v) ->
|
|
50
62
|
return if @disabled
|
|
51
63
|
@value = @value.filter (x) -> x isnt v
|
|
52
64
|
@emit 'change', @value
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@emit 'change', @value
|
|
66
|
+
_onRemoveMousedown: (e) ->
|
|
67
|
+
e.preventDefault()
|
|
68
|
+
e.stopPropagation()
|
|
69
|
+
@_blockOpenBriefly()
|
|
59
70
|
|
|
60
71
|
_onInput: (e) ->
|
|
61
72
|
query = e.target.value
|
|
62
73
|
open = true
|
|
63
74
|
highlightedIndex = if filtered.length > 0 then 0 else -1
|
|
64
75
|
|
|
65
|
-
|
|
76
|
+
_openMenu: ->
|
|
77
|
+
return if @disabled
|
|
78
|
+
return unless @_canOpen()
|
|
79
|
+
open = true
|
|
80
|
+
highlightedIndex = if filtered.length > 0 then Math.max(highlightedIndex, 0) else -1
|
|
81
|
+
|
|
82
|
+
_close: (restoreFocus = false, blockOpen = false) ->
|
|
66
83
|
open = false
|
|
67
84
|
query = ''
|
|
68
85
|
highlightedIndex = -1
|
|
86
|
+
@_blockOpenBriefly() if blockOpen
|
|
87
|
+
@_input?.focus() if restoreFocus
|
|
88
|
+
|
|
89
|
+
onFocusin: ->
|
|
90
|
+
return unless @_canOpen()
|
|
91
|
+
@_openMenu()
|
|
92
|
+
|
|
93
|
+
_onInputMousedown: (e) ->
|
|
94
|
+
return unless open and not query
|
|
95
|
+
e.preventDefault()
|
|
96
|
+
_ignoreInputClickOnce = true
|
|
97
|
+
@_close(false, true)
|
|
98
|
+
|
|
99
|
+
_onInputClick: ->
|
|
100
|
+
if _ignoreInputClickOnce
|
|
101
|
+
_ignoreInputClickOnce = false
|
|
102
|
+
return
|
|
103
|
+
return unless @_canOpen()
|
|
104
|
+
@_openMenu()
|
|
105
|
+
|
|
106
|
+
_onChipsClick: (e) ->
|
|
107
|
+
return unless e.target is e.currentTarget
|
|
108
|
+
if open and not query
|
|
109
|
+
@_close(false, true)
|
|
110
|
+
return
|
|
111
|
+
return unless @_canOpen()
|
|
69
112
|
@_input?.focus()
|
|
70
|
-
|
|
71
|
-
onFocusin: -> open = true
|
|
113
|
+
@_openMenu() if document.activeElement is @_input
|
|
72
114
|
|
|
73
115
|
onFocusout: ->
|
|
74
116
|
setTimeout =>
|
|
75
117
|
return if @_content?.contains(document.activeElement)
|
|
76
|
-
@_close()
|
|
118
|
+
@_close(false, true)
|
|
77
119
|
, 0
|
|
78
120
|
|
|
121
|
+
mounted: ->
|
|
122
|
+
_ready = true
|
|
123
|
+
|
|
79
124
|
_applyPlacement: ->
|
|
80
|
-
|
|
81
|
-
@_list.style.position = 'fixed'
|
|
82
|
-
@_list.style.inset = 'auto'
|
|
83
|
-
@_list.style.margin = '0'
|
|
84
|
-
@_list.style.positionArea = 'bottom start'
|
|
85
|
-
@_list.style.positionTry = 'flip-block, flip-inline, flip-block flip-inline'
|
|
86
|
-
@_list.style.positionVisibility = 'anchors-visible'
|
|
87
|
-
@_list.style.marginTop = '2px'
|
|
88
|
-
@_list.style.minWidth = 'anchor-size(width)'
|
|
125
|
+
ARIA.position @_content, @_list, placement: 'bottom start', offset: 2, matchWidth: true
|
|
89
126
|
|
|
90
127
|
_onKeydown: (e) ->
|
|
91
128
|
len = filtered.length
|
|
@@ -103,31 +140,31 @@ export MultiSelect = component
|
|
|
103
140
|
@_toggleItem(filtered[highlightedIndex])
|
|
104
141
|
when 'Escape'
|
|
105
142
|
e.preventDefault()
|
|
106
|
-
|
|
107
|
-
query = ''
|
|
143
|
+
@_close()
|
|
108
144
|
when 'Backspace'
|
|
109
145
|
if not query and @value.length > 0
|
|
110
146
|
@value = @value.slice(0, -1)
|
|
111
147
|
@emit 'change', @value
|
|
112
148
|
when 'Tab'
|
|
113
|
-
|
|
114
|
-
query = ''
|
|
149
|
+
@_close(false, true)
|
|
115
150
|
|
|
116
151
|
~>
|
|
152
|
+
return unless _ready
|
|
117
153
|
if @_list
|
|
118
|
-
@_list.setAttribute 'popover', '
|
|
154
|
+
@_list.setAttribute 'popover', 'manual'
|
|
119
155
|
@_applyPlacement()
|
|
120
156
|
ARIA.bindPopover open, (=> @_list), ((isOpen) => open = isOpen), (=> @_input)
|
|
157
|
+
ARIA.popupDismiss open, (=> @_list), (=> @_close(false, true)), [=> @_input, => @_content]
|
|
121
158
|
|
|
122
159
|
render
|
|
123
160
|
. ref: "_content", $open: open?!, $disabled: @disabled?!
|
|
124
161
|
|
|
125
162
|
# Chip area + input
|
|
126
|
-
. $chips: true, @click:
|
|
163
|
+
. $chips: true, @click: @_onChipsClick
|
|
127
164
|
for chip in @value
|
|
128
165
|
span $chip: true
|
|
129
166
|
"#{chip}"
|
|
130
|
-
button $remove: true, aria-label: "Remove #{chip}", @click: (=> @_removeChip(chip))
|
|
167
|
+
button $remove: true, aria-label: "Remove #{chip}", @mousedown: @_onRemoveMousedown, @click: (=> @_removeChip(chip))
|
|
131
168
|
"✕"
|
|
132
169
|
input ref: "_input", type: "text", autocomplete: "off"
|
|
133
170
|
role: "combobox"
|
|
@@ -138,14 +175,20 @@ export MultiSelect = component
|
|
|
138
175
|
disabled: @disabled
|
|
139
176
|
placeholder: if @value.length is 0 then @placeholder else ''
|
|
140
177
|
value: query
|
|
178
|
+
@mousedown: @_onInputMousedown
|
|
141
179
|
@input: @_onInput
|
|
180
|
+
@click: @_onInputClick
|
|
142
181
|
@keydown: @_onKeydown
|
|
143
|
-
if @value.length > 0
|
|
144
|
-
button $clear: true, aria-label: "Clear all", @click: @clearAll
|
|
145
|
-
"✕"
|
|
146
182
|
|
|
147
183
|
# Dropdown
|
|
148
|
-
div ref: "_list"
|
|
184
|
+
div ref: "_list"
|
|
185
|
+
id: _listId
|
|
186
|
+
role: "listbox"
|
|
187
|
+
popover: "manual"
|
|
188
|
+
hidden: not open
|
|
189
|
+
aria-hidden: (open ? undefined : "true")
|
|
190
|
+
$open: open?!
|
|
191
|
+
aria-multiselectable: "true"
|
|
149
192
|
style: "position:fixed;margin:0;inset:auto"
|
|
150
193
|
for item, idx in filtered
|
|
151
194
|
div role: "option", tabindex: "-1", id: "#{_listId}-#{idx}"
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
# a $link: true, href: "/about", "About"
|
|
14
14
|
|
|
15
15
|
export NavigationMenu = component
|
|
16
|
-
@orientation :=
|
|
17
|
-
@hoverDelay := 200
|
|
18
|
-
@hoverCloseDelay := 300
|
|
16
|
+
@orientation:: "horizontal" | "vertical" := "horizontal"
|
|
17
|
+
@hoverDelay:: number := 200
|
|
18
|
+
@hoverCloseDelay:: number := 300
|
|
19
19
|
|
|
20
20
|
activePanel := null
|
|
21
21
|
_ready := false
|
|
@@ -12,15 +12,15 @@ START_DELAY = 400
|
|
|
12
12
|
TICK_DELAY = 60
|
|
13
13
|
|
|
14
14
|
export NumberField = component
|
|
15
|
-
@value := 0
|
|
16
|
-
@min := null
|
|
17
|
-
@max := null
|
|
18
|
-
@step := 1
|
|
19
|
-
@smallStep := 0.1
|
|
20
|
-
@largeStep := 10
|
|
21
|
-
@disabled := false
|
|
22
|
-
@readOnly := false
|
|
23
|
-
@name := null
|
|
15
|
+
@value:: number := 0
|
|
16
|
+
@min:: any := null
|
|
17
|
+
@max:: any := null
|
|
18
|
+
@step:: number := 1
|
|
19
|
+
@smallStep:: number := 0.1
|
|
20
|
+
@largeStep:: number := 10
|
|
21
|
+
@disabled:: boolean := false
|
|
22
|
+
@readOnly:: boolean := false
|
|
23
|
+
@name:: any := null
|
|
24
24
|
|
|
25
25
|
_timer = null
|
|
26
26
|
_interval = null
|
|
@@ -87,7 +87,7 @@ export NumberField = component
|
|
|
87
87
|
document.removeEventListener 'pointerup', onUp
|
|
88
88
|
document.addEventListener 'pointerup', onUp
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
_onKeydown: (e) ->
|
|
91
91
|
return if @disabled or @readOnly
|
|
92
92
|
amount = @_stepAmount(e)
|
|
93
93
|
switch e.key
|
|
@@ -152,7 +152,7 @@ export NumberField = component
|
|
|
152
152
|
aria-readonly: @readOnly?!
|
|
153
153
|
disabled: @disabled
|
|
154
154
|
readonly: @readOnly
|
|
155
|
-
@keydown: @
|
|
155
|
+
@keydown: @_onKeydown
|
|
156
156
|
@blur: @_onBlur
|
|
157
157
|
|
|
158
158
|
button aria-label: "Increase", tabindex: "-1"
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
# OTPField length: 6, value <=> code, @complete: handleVerify
|
|
8
8
|
|
|
9
9
|
export OTPField = component
|
|
10
|
-
@length := 6
|
|
11
|
-
@value :=
|
|
12
|
-
@disabled := false
|
|
13
|
-
@mask := false
|
|
10
|
+
@length:: number := 6
|
|
11
|
+
@value:: string := ""
|
|
12
|
+
@disabled:: boolean := false
|
|
13
|
+
@mask:: boolean := false
|
|
14
14
|
|
|
15
15
|
_id =! "otp-#{Math.random().toString(36).slice(2, 8)}"
|
|
16
16
|
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
# Pagination page <=> currentPage, total: 500, perPage: 20, siblingCount: 2
|
|
9
9
|
|
|
10
10
|
export Pagination = component
|
|
11
|
-
@page := 1
|
|
12
|
-
@total := 0
|
|
13
|
-
@perPage := 10
|
|
14
|
-
@siblingCount := 1
|
|
11
|
+
@page:: number := 1
|
|
12
|
+
@total:: number := 0
|
|
13
|
+
@perPage:: number := 10
|
|
14
|
+
@siblingCount:: number := 1
|
|
15
15
|
|
|
16
16
|
totalPages ~= Math.max(1, Math.ceil(@total / @perPage))
|
|
17
17
|
_ready := false
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
# p "Popover content"
|
|
11
11
|
|
|
12
12
|
export Popover = component
|
|
13
|
-
@placement :=
|
|
14
|
-
@offset := 4
|
|
15
|
-
@disabled := false
|
|
16
|
-
@openOnHover := false
|
|
17
|
-
@hoverDelay := 300
|
|
18
|
-
@hoverCloseDelay := 200
|
|
13
|
+
@placement:: "top" | "top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "right" := "bottom-start"
|
|
14
|
+
@offset:: number := 4
|
|
15
|
+
@disabled:: boolean := false
|
|
16
|
+
@openOnHover:: boolean := false
|
|
17
|
+
@hoverDelay:: number := 300
|
|
18
|
+
@hoverCloseDelay:: number := 200
|
|
19
19
|
|
|
20
20
|
open := false
|
|
21
21
|
_ready := false
|
|
@@ -24,26 +24,11 @@ export Popover = component
|
|
|
24
24
|
_id =! "pop-#{Math.random().toString(36).slice(2, 8)}"
|
|
25
25
|
|
|
26
26
|
_applyPlacement: ->
|
|
27
|
+
trigger = @_content?.querySelector('[data-trigger]')
|
|
27
28
|
floating = @_content?.querySelector('[data-content]')
|
|
28
|
-
return unless floating
|
|
29
29
|
[side, align] = @placement.split('-')
|
|
30
|
-
align
|
|
31
|
-
|
|
32
|
-
floating.style.position = 'fixed'
|
|
33
|
-
floating.style.inset = 'auto'
|
|
34
|
-
floating.style.margin = '0'
|
|
35
|
-
floating.style.positionArea = area
|
|
36
|
-
floating.style.positionTry = 'flip-block, flip-inline, flip-block flip-inline'
|
|
37
|
-
floating.style.positionVisibility = 'anchors-visible'
|
|
38
|
-
floating.style.marginTop = ''
|
|
39
|
-
floating.style.marginRight = ''
|
|
40
|
-
floating.style.marginBottom = ''
|
|
41
|
-
floating.style.marginLeft = ''
|
|
42
|
-
switch side
|
|
43
|
-
when 'bottom' then floating.style.marginTop = "#{@offset}px"
|
|
44
|
-
when 'top' then floating.style.marginBottom = "#{@offset}px"
|
|
45
|
-
when 'left' then floating.style.marginRight = "#{@offset}px"
|
|
46
|
-
when 'right' then floating.style.marginLeft = "#{@offset}px"
|
|
30
|
+
align ??= 'center'
|
|
31
|
+
ARIA.position trigger, floating, placement: "#{side} #{align}", offset: @offset
|
|
47
32
|
|
|
48
33
|
mounted: ->
|
|
49
34
|
_ready = true
|
|
@@ -89,6 +74,8 @@ export Popover = component
|
|
|
89
74
|
if trigger
|
|
90
75
|
trigger.setAttribute 'aria-expanded', !!open
|
|
91
76
|
if floating
|
|
77
|
+
floating.hidden = not open
|
|
78
|
+
if open then floating.removeAttribute 'aria-hidden' else floating.setAttribute 'aria-hidden', 'true'
|
|
92
79
|
floating.setAttribute 'data-placement', @placement
|
|
93
80
|
if open then floating.setAttribute 'data-open', '' else floating.removeAttribute 'data-open'
|
|
94
81
|
ARIA.wireAria floating, _id
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
# p "User details here..."
|
|
12
12
|
|
|
13
13
|
export PreviewCard = component
|
|
14
|
-
@delay := 400
|
|
15
|
-
@closeDelay := 200
|
|
14
|
+
@delay:: number := 400
|
|
15
|
+
@closeDelay:: number := 200
|
|
16
16
|
|
|
17
17
|
open := false
|
|
18
18
|
_ready := false
|
|
@@ -42,21 +42,15 @@ export PreviewCard = component
|
|
|
42
42
|
@_applyPlacement()
|
|
43
43
|
trigger.addEventListener 'focus', =>
|
|
44
44
|
clearTimeout _closeTimer if _closeTimer
|
|
45
|
-
_openTimer = setTimeout (=> open = true; @
|
|
45
|
+
_openTimer = setTimeout (=> open = true; @_applyPlacement()), @delay
|
|
46
46
|
trigger.addEventListener 'blur', =>
|
|
47
47
|
clearTimeout _openTimer if _openTimer
|
|
48
48
|
_closeTimer = setTimeout (=> open = false), @closeDelay
|
|
49
49
|
|
|
50
50
|
_applyPlacement: ->
|
|
51
|
+
trigger = @_root?.querySelector('[data-trigger]')
|
|
51
52
|
floating = @_root?.querySelector('[data-content]')
|
|
52
|
-
|
|
53
|
-
floating.style.position = 'fixed'
|
|
54
|
-
floating.style.inset = 'auto'
|
|
55
|
-
floating.style.margin = '0'
|
|
56
|
-
floating.style.positionArea = 'bottom start'
|
|
57
|
-
floating.style.positionTry = 'flip-block, flip-inline, flip-block flip-inline'
|
|
58
|
-
floating.style.positionVisibility = 'anchors-visible'
|
|
59
|
-
floating.style.marginTop = '4px'
|
|
53
|
+
ARIA.position trigger, floating, placement: 'bottom start', offset: 4
|
|
60
54
|
|
|
61
55
|
~>
|
|
62
56
|
return unless _ready
|
|
@@ -64,6 +58,8 @@ export PreviewCard = component
|
|
|
64
58
|
floating = @_root?.querySelector('[data-content]')
|
|
65
59
|
return unless floating and trigger
|
|
66
60
|
trigger.setAttribute 'aria-expanded', !!open
|
|
61
|
+
floating.hidden = not open
|
|
62
|
+
if open then floating.removeAttribute 'aria-hidden' else floating.setAttribute 'aria-hidden', 'true'
|
|
67
63
|
@_applyPlacement()
|
|
68
64
|
if open then floating.setAttribute('data-open', '') else floating.removeAttribute('data-open')
|
|
69
65
|
ARIA.bindPopover open, (=> floating), ((isOpen) => open = isOpen), (=> trigger)
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
# div $value: "lg", "Large"
|
|
11
11
|
|
|
12
12
|
export RadioGroup = component
|
|
13
|
-
@value := null
|
|
14
|
-
@disabled := false
|
|
15
|
-
@orientation :=
|
|
16
|
-
@name :=
|
|
13
|
+
@value:: any := null
|
|
14
|
+
@disabled:: boolean := false
|
|
15
|
+
@orientation:: "horizontal" | "vertical" := "vertical"
|
|
16
|
+
@name:: string := ""
|
|
17
17
|
|
|
18
18
|
_options ~=
|
|
19
19
|
return [] unless @_slot
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
# div $panel: true, "Bottom"
|
|
20
20
|
|
|
21
21
|
export Resizable = component
|
|
22
|
-
@orientation :=
|
|
23
|
-
@minSize := 10
|
|
24
|
-
@maxSize := 90
|
|
22
|
+
@orientation:: "horizontal" | "vertical" := "horizontal"
|
|
23
|
+
@minSize:: number := 10
|
|
24
|
+
@maxSize:: number := 90
|
|
25
25
|
|
|
26
26
|
_ready := false
|
|
27
27
|
_dragging = null
|