Module: UI::ResizableHandleBehavior

Included in:
ResizableHandle, ResizableHandleComponent
Defined in:
app/behaviors/ui/resizable_handle_behavior.rb

Overview

Shared behavior for ResizableHandle component Handles data attributes for resize handles

Instance Method Summary collapse

Instance Method Details

#grip_container_classesObject

CSS classes for the grip icon container (when with_handle is true)



76
77
78
79
80
# File 'app/behaviors/ui/resizable_handle_behavior.rb', line 76

def grip_container_classes
  [
    "z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border"
  ].join(" ")
end

#handle_actionsObject

Stimulus actions for the handle



47
48
49
50
51
52
53
54
55
# File 'app/behaviors/ui/resizable_handle_behavior.rb', line 47

def handle_actions
  [
    "pointerdown->ui--resizable#startDrag",
    "pointerenter->ui--resizable#handleEnter",
    "pointerleave->ui--resizable#handleLeave",
    "focus->ui--resizable#handleFocus",
    "blur->ui--resizable#handleBlur"
  ].join(" ")
end

#handle_base_classesObject

Base CSS classes for the handle The handle uses a thin visual line (w-px) but has padding for easier interaction



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'app/behaviors/ui/resizable_handle_behavior.rb', line 8

def handle_base_classes
  base = [
    "relative z-10 flex shrink-0 items-center justify-center",
    "w-2 -mx-[3.5px]", # 8px wide handle with negative margin to overlap panels
    "bg-transparent cursor-col-resize",
    "touch-none select-none", # Prevent scroll interference on touch devices
    # The visible line is drawn with ::after
    "after:absolute after:inset-y-0 after:left-1/2 after:w-px after:-translate-x-1/2 after:bg-border",
    "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1",
    # Vertical direction
    "data-[panel-group-direction=vertical]:h-2 data-[panel-group-direction=vertical]:w-full",
    "data-[panel-group-direction=vertical]:-my-[3.5px] data-[panel-group-direction=vertical]:mx-0",
    "data-[panel-group-direction=vertical]:cursor-row-resize",
    "data-[panel-group-direction=vertical]:after:inset-x-0 data-[panel-group-direction=vertical]:after:inset-y-auto",
    "data-[panel-group-direction=vertical]:after:top-1/2 data-[panel-group-direction=vertical]:after:left-0",
    "data-[panel-group-direction=vertical]:after:h-px data-[panel-group-direction=vertical]:after:w-full",
    "data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0",
    "[&[data-panel-group-direction=vertical]>div]:rotate-90"
  ]
  base << @classes if @classes.present?
  base.join(" ")
end

#handle_data_attributesObject

Generate data attributes for the handle



32
33
34
35
36
37
38
# File 'app/behaviors/ui/resizable_handle_behavior.rb', line 32

def handle_data_attributes
  {
    ui__resizable_target: "handle",
    resize_handle: "",
    resize_handle_state: "inactive"
  }
end

#handle_html_attributesObject

Build complete HTML attributes hash for handle



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'app/behaviors/ui/resizable_handle_behavior.rb', line 58

def handle_html_attributes
  base_attrs = @attributes&.except(:data) || {}
  data_attrs = merged_handle_data_attributes
  data_attrs[:action] = handle_actions

  base_attrs.merge(
    class: handle_base_classes,
    "data-slot": "resizable-handle",
    tabindex: "0",
    role: "separator",
    "aria-valuenow": "50",
    "aria-valuemin": "0",
    "aria-valuemax": "100",
    data: data_attrs
  )
end

#merged_handle_data_attributesObject

Merge user-provided data attributes with handle data



41
42
43
44
# File 'app/behaviors/ui/resizable_handle_behavior.rb', line 41

def merged_handle_data_attributes
  user_data = @attributes&.fetch(:data, {}) || {}
  user_data.merge(handle_data_attributes)
end