rip-lang 3.13.93 → 3.13.95

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.
Files changed (63) hide show
  1. package/README.md +1 -1
  2. package/docs/dist/rip.js +142 -38
  3. package/docs/dist/rip.min.js +174 -174
  4. package/docs/dist/rip.min.js.br +0 -0
  5. package/package.json +1 -1
  6. package/src/ui.rip +65 -0
  7. package/docs/ui/accordion.rip +0 -113
  8. package/docs/ui/alert-dialog.rip +0 -96
  9. package/docs/ui/autocomplete.rip +0 -141
  10. package/docs/ui/avatar.rip +0 -37
  11. package/docs/ui/badge.rip +0 -15
  12. package/docs/ui/breadcrumb.rip +0 -46
  13. package/docs/ui/button-group.rip +0 -26
  14. package/docs/ui/button.rip +0 -23
  15. package/docs/ui/card.rip +0 -25
  16. package/docs/ui/carousel.rip +0 -110
  17. package/docs/ui/checkbox-group.rip +0 -65
  18. package/docs/ui/checkbox.rip +0 -33
  19. package/docs/ui/collapsible.rip +0 -50
  20. package/docs/ui/combobox.rip +0 -155
  21. package/docs/ui/context-menu.rip +0 -105
  22. package/docs/ui/date-picker.rip +0 -214
  23. package/docs/ui/dialog.rip +0 -107
  24. package/docs/ui/drawer.rip +0 -79
  25. package/docs/ui/editable-value.rip +0 -80
  26. package/docs/ui/field.rip +0 -53
  27. package/docs/ui/fieldset.rip +0 -22
  28. package/docs/ui/form.rip +0 -39
  29. package/docs/ui/grid.rip +0 -901
  30. package/docs/ui/hljs-rip.js +0 -209
  31. package/docs/ui/index.css +0 -1772
  32. package/docs/ui/index.html +0 -2433
  33. package/docs/ui/input-group.rip +0 -28
  34. package/docs/ui/input.rip +0 -36
  35. package/docs/ui/label.rip +0 -16
  36. package/docs/ui/menu.rip +0 -162
  37. package/docs/ui/menubar.rip +0 -155
  38. package/docs/ui/meter.rip +0 -36
  39. package/docs/ui/multi-select.rip +0 -158
  40. package/docs/ui/native-select.rip +0 -32
  41. package/docs/ui/nav-menu.rip +0 -129
  42. package/docs/ui/number-field.rip +0 -162
  43. package/docs/ui/otp-field.rip +0 -89
  44. package/docs/ui/pagination.rip +0 -123
  45. package/docs/ui/popover.rip +0 -143
  46. package/docs/ui/preview-card.rip +0 -73
  47. package/docs/ui/progress.rip +0 -25
  48. package/docs/ui/radio-group.rip +0 -67
  49. package/docs/ui/resizable.rip +0 -123
  50. package/docs/ui/scroll-area.rip +0 -145
  51. package/docs/ui/select.rip +0 -184
  52. package/docs/ui/separator.rip +0 -17
  53. package/docs/ui/skeleton.rip +0 -22
  54. package/docs/ui/slider.rip +0 -165
  55. package/docs/ui/spinner.rip +0 -17
  56. package/docs/ui/table.rip +0 -27
  57. package/docs/ui/tabs.rip +0 -124
  58. package/docs/ui/textarea.rip +0 -48
  59. package/docs/ui/toast.rip +0 -87
  60. package/docs/ui/toggle-group.rip +0 -78
  61. package/docs/ui/toggle.rip +0 -24
  62. package/docs/ui/toolbar.rip +0 -46
  63. package/docs/ui/tooltip.rip +0 -115
@@ -1,110 +0,0 @@
1
- # Carousel — accessible headless slide carousel
2
- #
3
- # Displays one slide at a time with arrow key navigation, optional
4
- # autoplay, and loop mode. Discovers slides from [data-slide] children.
5
- # Ships zero CSS.
6
- #
7
- # Usage:
8
- # Carousel loop: true
9
- # div $slide: true
10
- # img src: "slide1.jpg"
11
- # div $slide: true
12
- # img src: "slide2.jpg"
13
- # div $slide: true
14
- # img src: "slide3.jpg"
15
- #
16
- # Carousel autoplay: true, interval: 5000, @change: handleSlide
17
- # div $slide: true, "Slide A"
18
- # div $slide: true, "Slide B"
19
-
20
- export Carousel = component
21
- @orientation := 'horizontal'
22
- @loop := false
23
- @autoplay := false
24
- @interval := 4000
25
- @label := 'Carousel'
26
-
27
- activeIndex := 0
28
- _ready := false
29
- _timer = null
30
-
31
- _slides ~=
32
- return [] unless _ready
33
- return [] unless @_content
34
- Array.from(@_content.querySelectorAll('[data-slide]') or [])
35
-
36
- totalSlides ~= _slides.length
37
-
38
- mounted: ->
39
- _ready = true
40
- @_startAutoplay() if @autoplay
41
-
42
- beforeUnmount: ->
43
- @_stopAutoplay()
44
-
45
- _startAutoplay: ->
46
- @_stopAutoplay()
47
- _timer = setInterval (=> @next()), @interval
48
-
49
- _stopAutoplay: ->
50
- clearInterval _timer if _timer
51
- _timer = null
52
-
53
- goto: (idx) ->
54
- count = totalSlides
55
- return unless count
56
- if @loop
57
- idx = idx %% count
58
- else
59
- idx = Math.max(0, Math.min(idx, count - 1))
60
- activeIndex = idx
61
- @emit 'change', activeIndex
62
-
63
- next: -> @goto(activeIndex + 1)
64
- prev: -> @goto(activeIndex - 1)
65
-
66
- onKeydown: (e) ->
67
- horiz = @orientation is 'horizontal'
68
- switch e.key
69
- when (if horiz then 'ArrowRight' else 'ArrowDown')
70
- e.preventDefault()
71
- @next()
72
- when (if horiz then 'ArrowLeft' else 'ArrowUp')
73
- e.preventDefault()
74
- @prev()
75
- when 'Home'
76
- e.preventDefault()
77
- @goto(0)
78
- when 'End'
79
- e.preventDefault()
80
- @goto(totalSlides - 1)
81
-
82
- ~>
83
- return unless _ready
84
- _slides.forEach (el, idx) =>
85
- isActive = idx is activeIndex
86
- el.hidden = not isActive
87
- el.toggleAttribute 'data-active', isActive
88
- el.setAttribute 'role', 'tabpanel'
89
- el.setAttribute 'aria-roledescription', 'slide'
90
- el.setAttribute 'aria-label', "Slide #{idx + 1} of #{totalSlides}"
91
-
92
- onMouseenter: -> @_stopAutoplay() if @autoplay
93
- onMouseleave: -> @_startAutoplay() if @autoplay
94
-
95
- render
96
- div role: "region", aria-roledescription: "carousel", aria-label: @label, tabindex: "0"
97
- $orientation: @orientation
98
- @keydown: @onKeydown
99
- @mouseenter: @onMouseenter
100
- @mouseleave: @onMouseleave
101
- button $prev: true, aria-label: "Previous slide"
102
- disabled: not @loop and activeIndex <= 0
103
- $disabled: (not @loop and activeIndex <= 0)?!
104
- @click: (=> @prev())
105
- div ref: "_content"
106
- slot
107
- button $next: true, aria-label: "Next slide"
108
- disabled: not @loop and activeIndex >= totalSlides - 1
109
- $disabled: (not @loop and activeIndex >= totalSlides - 1)?!
110
- @click: (=> @next())
@@ -1,65 +0,0 @@
1
- # CheckboxGroup — accessible headless checkbox group
2
- #
3
- # Multiple options can be checked independently. Wraps individual checkboxes
4
- # with group semantics. Value is an array of checked option values.
5
- # Ships zero CSS.
6
- #
7
- # Usage:
8
- # CheckboxGroup value <=> selectedToppings
9
- # div $value: "cheese", "Cheese"
10
- # div $value: "bacon", "Bacon"
11
- # div $value: "lettuce", "Lettuce"
12
-
13
- export CheckboxGroup = component
14
- @value := []
15
- @disabled := false
16
- @orientation := 'vertical'
17
- @label := ''
18
-
19
- _options ~=
20
- return [] unless @_slot
21
- Array.from(@_slot.querySelectorAll('[data-value]') or [])
22
-
23
- _isChecked: (val) ->
24
- Array.isArray(@value) and val in @value
25
-
26
- _toggle: (val) ->
27
- return if @disabled
28
- arr = if Array.isArray(@value) then [...@value] else []
29
- if val in arr
30
- arr = arr.filter (v) -> v isnt val
31
- else
32
- arr.push val
33
- @value = arr
34
- @emit 'change', @value
35
-
36
- onKeydown: (e) ->
37
- boxes = @_root?.querySelectorAll('[role="checkbox"]')
38
- return unless boxes?.length
39
- focused = Array.from(boxes).indexOf(document.activeElement)
40
- return if focused < 0
41
- len = boxes.length
42
- switch e.key
43
- when 'ArrowDown', 'ArrowRight'
44
- e.preventDefault()
45
- boxes[(focused + 1) %% len]?.focus()
46
- when 'ArrowUp', 'ArrowLeft'
47
- e.preventDefault()
48
- boxes[(focused - 1) %% len]?.focus()
49
-
50
- render
51
- div ref: "_root", role: "group", aria-label: @label or undefined, aria-orientation: @orientation
52
- $orientation: @orientation
53
- $disabled: @disabled?!
54
-
55
- . ref: "_slot", style: "display:none"
56
- slot
57
-
58
- for opt, idx in _options
59
- button role: "checkbox", tabindex: (if idx is 0 then "0" else "-1")
60
- aria-checked: !!@_isChecked(opt.dataset.value)
61
- $checked: @_isChecked(opt.dataset.value)?!
62
- $disabled: @disabled?!
63
- $value: opt.dataset.value
64
- @click: (=> @_toggle(opt.dataset.value))
65
- = opt.textContent
@@ -1,33 +0,0 @@
1
- # Checkbox — accessible headless checkbox/switch widget
2
- #
3
- # Toggles on click, Enter, or Space. Supports indeterminate state.
4
- # Exposes $checked, $indeterminate, $disabled. Ships zero CSS.
5
- # Set @switch to true for switch semantics (role="switch").
6
- #
7
- # Usage:
8
- # Checkbox checked <=> isActive, @change: handleChange
9
- # span "Enable notifications"
10
- #
11
- # Checkbox checked <=> isDark, switch: true
12
- # span "Dark mode"
13
-
14
- export Checkbox = component
15
- @checked := false
16
- @disabled := false
17
- @indeterminate := false
18
- @switch := false
19
-
20
- onClick: ->
21
- return if @disabled
22
- @indeterminate = false
23
- @checked = not @checked
24
- @emit 'change', @checked
25
-
26
- render
27
- button role: @switch ? 'switch' : 'checkbox'
28
- aria-checked: @indeterminate ? 'mixed' : !!@checked
29
- aria-disabled: @disabled?!
30
- $checked: @checked?!
31
- $indeterminate: @indeterminate?!
32
- $disabled: @disabled?!
33
- slot
@@ -1,50 +0,0 @@
1
- # Collapsible — accessible headless expand/collapse section
2
- #
3
- # Single open/close section. Simpler than Accordion (no item IDs,
4
- # no single/multiple mode). Exposes content dimensions as CSS
5
- # custom properties for animated expand/collapse. Ships zero CSS.
6
- #
7
- # Usage:
8
- # Collapsible open <=> isOpen
9
- # button $trigger: true, "Show details"
10
- # div $content: true
11
- # p "Hidden content here"
12
-
13
- export Collapsible = component
14
- @open := false
15
- @disabled := false
16
-
17
- _ready := false
18
-
19
- mounted: ->
20
- _ready = true
21
- trigger = @_root?.querySelector('[data-trigger]')
22
- return unless trigger
23
- trigger.addEventListener 'click', => @toggle() unless @disabled
24
- trigger.addEventListener 'keydown', (e) =>
25
- if e.key in ['Enter', ' '] and not @disabled
26
- e.preventDefault()
27
- @toggle()
28
-
29
- toggle: ->
30
- @open = not @open
31
- @emit 'change', @open
32
-
33
- ~>
34
- return unless _ready
35
- trigger = @_root?.querySelector('[data-trigger]')
36
- content = @_root?.querySelector('[data-content]')
37
- if trigger
38
- trigger.setAttribute 'aria-expanded', !!@open
39
- trigger.setAttribute 'aria-disabled', true if @disabled
40
- trigger.tabIndex = if @disabled then -1 else 0
41
- if content
42
- content.hidden = not @open
43
- if @open
44
- rect = content.getBoundingClientRect()
45
- content.style.setProperty '--collapsible-height', "#{rect.height}px"
46
- content.style.setProperty '--collapsible-width', "#{rect.width}px"
47
-
48
- render
49
- div ref: "_root", $open: @open?!, $disabled: @disabled?!
50
- slot
@@ -1,155 +0,0 @@
1
- # Combobox — accessible headless combobox (input + filterable listbox)
2
- #
3
- # Keyboard: ArrowDown/Up to navigate, Enter to select, Escape to close,
4
- # typing filters the list via the @filter callback.
5
- #
6
- # Exposes $open on the wrapper, $highlighted on options.
7
- # Ships zero CSS — style entirely via attribute selectors in your stylesheet.
8
- #
9
- # Usage:
10
- # Combobox query <=> searchText, items: fruits, @select: handleSelect, @filter: filterFn
11
-
12
- export Combobox = component
13
- @query := ''
14
- @items := []
15
- @placeholder := 'Search...'
16
- @disabled := false
17
- @autoHighlight := true
18
-
19
- open := false
20
- highlightedIndex := -1
21
- _listId =! "cb-#{Math.random().toString(36).slice(2, 8)}"
22
-
23
- getItems: ->
24
- return [] unless @_list
25
- Array.from(@_list.querySelectorAll('[role="option"]'))
26
-
27
- _scrollToItem: ->
28
- @getItems()[highlightedIndex]?.scrollIntoView({ block: 'nearest' })
29
-
30
- clear: ->
31
- @query = ''
32
- highlightedIndex = -1
33
- @emit 'filter', ''
34
-
35
- onInput: (e) ->
36
- @query = e.target.value
37
- open = true
38
- highlightedIndex = if @autoHighlight and @items.length > 0 then 0 else -1
39
- @emit 'filter', @query
40
-
41
- onFocusin: -> @openMenu()
42
-
43
- onFocusout: (e) ->
44
- unless @_content?.contains(e.relatedTarget)
45
- @close()
46
-
47
- openMenu: ->
48
- open = true
49
- highlightedIndex = -1
50
- setTimeout => @_position(), 0
51
-
52
- close: ->
53
- open = false
54
- highlightedIndex = -1
55
-
56
- _position: ->
57
- return unless @_input and @_list
58
- tr = @_input.getBoundingClientRect()
59
- @_list.style.left = "#{tr.left}px"
60
- @_list.style.top = "#{tr.bottom + 2}px"
61
- @_list.style.minWidth = "#{tr.width}px"
62
- fl = @_list.getBoundingClientRect()
63
- if fl.bottom > window.innerHeight
64
- @_list.style.top = "#{tr.top - fl.height - 2}px"
65
-
66
- isDisabled: (item) -> item?.hasAttribute?('data-disabled')
67
-
68
- selectIndex: (idx) ->
69
- item = @getItems()[idx]
70
- return unless item
71
- return if @isDisabled(item)
72
- val = item.dataset.value ?? item.textContent.trim()
73
- @query = val
74
- @emit 'select', val
75
- @close()
76
- @_input?.blur()
77
-
78
- _nextEnabled: (from, dir) ->
79
- opts = @getItems()
80
- len = opts.length
81
- i = from
82
- loop len
83
- i = (i + dir) %% len
84
- return i unless @isDisabled(opts[i])
85
- from
86
-
87
- _onKeydown: (e) ->
88
- len = @getItems().length
89
- switch e.key
90
- when 'ArrowDown'
91
- e.preventDefault()
92
- @openMenu() unless open
93
- highlightedIndex = @_nextEnabled(highlightedIndex, 1)
94
- @_scrollToItem()
95
- when 'ArrowUp'
96
- e.preventDefault()
97
- highlightedIndex = @_nextEnabled(highlightedIndex, -1)
98
- @_scrollToItem()
99
- when 'Enter'
100
- e.preventDefault()
101
- if highlightedIndex >= 0
102
- @selectIndex(highlightedIndex)
103
- else if len is 1
104
- @selectIndex(0)
105
- when 'Escape'
106
- e.preventDefault()
107
- if open then @close() else @query = ''
108
- when 'Tab'
109
- @close()
110
-
111
- ~>
112
- if open
113
- onDown = (e) =>
114
- root = @_content
115
- unless root?.contains(e.target)
116
- @close()
117
- document.addEventListener 'mousedown', onDown
118
- return -> document.removeEventListener 'mousedown', onDown
119
-
120
- render
121
- . ref: "_content", $open: open?!
122
-
123
- # Text input
124
- . style: "position:relative;display:inline-flex;align-items:center"
125
- input ref: "_input", role: "combobox"
126
- type: "text"
127
- autocomplete: "off"
128
- aria-expanded: !!open
129
- aria-haspopup: "listbox"
130
- aria-autocomplete: "list"
131
- aria-controls: if open then _listId else undefined
132
- aria-activedescendant: if highlightedIndex >= 0 then "#{_listId}-#{highlightedIndex}" else undefined
133
- $disabled: @disabled?!
134
- disabled: @disabled
135
- placeholder: @placeholder
136
- value: @query
137
- @keydown: @_onKeydown
138
- if @query
139
- button aria-label: "Clear", $clear: true, @click: @clear
140
- "✕"
141
-
142
- # Listbox — conditionally rendered (like Select)
143
- if open and @items.length > 0
144
- div ref: "_list", id: _listId, role: "listbox", $open: true
145
- style: "position:fixed"
146
- for item, idx in @items
147
- div role: "option", tabindex: "-1", id: "#{_listId}-#{idx}"
148
- $value: item
149
- $highlighted: (idx is highlightedIndex)?!
150
- @click: (=> @selectIndex(idx))
151
- @mouseenter: (=> highlightedIndex = idx)
152
- "#{item}"
153
- if open and @items.length is 0 and @query
154
- div role: "status", aria-live: "polite", $empty: true
155
- "No results"
@@ -1,105 +0,0 @@
1
- # ContextMenu — accessible headless right-click menu
2
- #
3
- # Opens on contextmenu event (right-click) over the trigger area.
4
- # Keyboard navigation matches Menu. Ships zero CSS.
5
- #
6
- # Usage:
7
- # ContextMenu @select: handleAction
8
- # div $trigger: true
9
- # p "Right-click this area"
10
- # div $item: "cut", "Cut"
11
- # div $item: "copy", "Copy"
12
- # div $item: "paste", "Paste"
13
-
14
- export ContextMenu = component
15
- @disabled := false
16
-
17
- open := false
18
- highlightedIndex := -1
19
- posX := 0
20
- posY := 0
21
-
22
- _menuItems ~=
23
- return [] unless @_slot
24
- Array.from(@_slot.querySelectorAll('[data-item]') or [])
25
-
26
- _triggerEl ~=
27
- return null unless @_slot
28
- @_slot.querySelector('[data-trigger]')
29
-
30
- _onContextMenu: (e) ->
31
- return if @disabled
32
- e.preventDefault()
33
- posX = e.clientX
34
- posY = e.clientY
35
- open = true
36
- highlightedIndex = 0
37
- requestAnimationFrame =>
38
- @_list?.querySelectorAll('[role="menuitem"]')[0]?.focus()
39
-
40
- close: ->
41
- open = false
42
- highlightedIndex = -1
43
-
44
- selectIndex: (idx) ->
45
- item = _menuItems[idx]
46
- return unless item
47
- return if item.dataset.disabled?
48
- @emit 'select', item.dataset.item
49
- @close()
50
-
51
- _onKeydown: (e) ->
52
- len = _menuItems.length
53
- return unless len
54
- switch e.key
55
- when 'ArrowDown'
56
- e.preventDefault()
57
- highlightedIndex = (highlightedIndex + 1) %% len
58
- @_list?.querySelectorAll('[role="menuitem"]')[highlightedIndex]?.focus()
59
- when 'ArrowUp'
60
- e.preventDefault()
61
- highlightedIndex = (highlightedIndex - 1) %% len
62
- @_list?.querySelectorAll('[role="menuitem"]')[highlightedIndex]?.focus()
63
- when 'Home'
64
- e.preventDefault()
65
- highlightedIndex = 0
66
- @_list?.querySelectorAll('[role="menuitem"]')[0]?.focus()
67
- when 'End'
68
- e.preventDefault()
69
- highlightedIndex = len - 1
70
- @_list?.querySelectorAll('[role="menuitem"]')[len - 1]?.focus()
71
- when 'Enter', ' '
72
- e.preventDefault()
73
- @selectIndex(highlightedIndex)
74
- when 'Escape', 'Tab'
75
- e.preventDefault() if e.key is 'Escape'
76
- @close()
77
-
78
- ~>
79
- if open
80
- onDown = (e) =>
81
- unless @_list?.contains(e.target)
82
- @close()
83
- document.addEventListener 'mousedown', onDown
84
- return -> document.removeEventListener 'mousedown', onDown
85
-
86
- render
87
- . @contextmenu: @_onContextMenu
88
-
89
- . ref: "_slot", style: "display:none"
90
- slot
91
-
92
- if _triggerEl
93
- . innerHTML: _triggerEl.innerHTML
94
-
95
- if open
96
- div ref: "_list", role: "menu", $open: true, @keydown: @_onKeydown
97
- style: "position:fixed;left:#{posX}px;top:#{posY}px;z-index:50"
98
- for item, idx in _menuItems
99
- div role: "menuitem", tabindex: "-1"
100
- $highlighted: (idx is highlightedIndex)?!
101
- $disabled: item.dataset.disabled?!
102
- $value: item.dataset.item
103
- @click: (=> @selectIndex(idx))
104
- @mouseenter: (=> highlightedIndex = idx)
105
- = item.textContent