Class: ShadcnPhlexcomponents::Base

Inherits:
Phlex::HTML
  • Object
show all
Includes:
ClassVariants::Helper, Phlex::Rails::Helpers::ButtonTo, Phlex::Rails::Helpers::LinkTo, Phlex::Rails::Helpers::Sanitize
Defined in:
lib/shadcn_phlexcomponents/components/base.rb

Direct Known Subclasses

Accordion, AccordionContent, AccordionContentContainer, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AspectRatio, AspectRatioContainer, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, CheckboxGroup, CheckboxGroupItemContainer, CheckboxIndicator, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxContent, ComboboxContentContainer, ComboboxGroup, ComboboxItem, ComboboxLabel, ComboboxListContainer, ComboboxSearchInput, ComboboxSearchInputContainer, ComboboxSeparator, ComboboxText, ComboboxTrigger, ComboboxTriggerText, Command, CommandContent, CommandFooter, CommandGroup, CommandItem, CommandKbd, CommandLabel, CommandListContainer, CommandSearchInput, CommandSearchInputContainer, CommandText, CommandTrigger, DatePicker, DatePickerContent, DatePickerContentContainer, DatePickerInput, DatePickerInputContainer, DatePickerTrigger, DateRangePicker, Dialog, DialogClose, DialogCloseIcon, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuContentContainer, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubContentContainer, DropdownMenuSubTrigger, DropdownMenuTrigger, Form, FormCheckbox, FormCheckboxGroup, FormCombobox, FormDatePicker, FormDateRangePicker, FormError, FormField, FormHint, FormInput, FormRadioGroup, FormSelect, FormSlider, FormSwitch, FormTextarea, HoverCard, HoverCardContent, HoverCardContentContainer, HoverCardTrigger, Input, Label, Link, LoadingButton, Pagination, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverContent, PopoverContentContainer, PopoverTrigger, Progress, ProgressIndicator, RadioGroup, RadioGroupItem, RadioGroupItemIndicator, Select, SelectContent, SelectContentContainer, SelectGroup, SelectItem, SelectItemIndicator, SelectLabel, SelectSeparator, SelectTrigger, Separator, Sheet, SheetClose, SheetCloseIcon, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Skeleton, Slider, Switch, SwitchThumb, Table, TableBody, TableCaption, TableCell, TableContainer, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeSwitcher, Toast, ToastAction, ToastContainer, ToastContent, ToastDescription, ToastTitle, Toggle, Tooltip, TooltipArrow, TooltipContent, TooltipTrigger

Constant Summary collapse

TAILWIND_MERGER =
::TailwindMerge::Merger.new.freeze
SANITIZER_ALLOWED_TAGS =
(Rails::HTML::SafeListSanitizer.allowed_tags.to_a +
["svg", "path", "polygon", "polyline", "circle", "ellipse", "rect", "line", "use", "defs", "g"]).freeze
SANITIZER_ALLOWED_ATTRIBUTES =
(Rails::HTML::SafeListSanitizer.allowed_attributes.to_a +
[
  "viewBox",
  "preserveaspectratio",
  "cx",
  "cy",
  "d",
  "fill",
  "height",
  "points",
  "r",
  "stroke",
  "width",
  "x",
  "y",
  "stroke-linejoin",
  "stroke-width",
  "stroke-linecap",
  "aria-hidden",
  "class",
  "x1",
  "x2",
  "y1",
  "y2",
]).freeze

Instance Method Summary collapse

Constructor Details

#initialize(**attributes) ⇒ Base

Returns a new instance of Base.



41
42
43
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 41

def initialize(**attributes)
  merge_default_attributes(attributes)
end

Instance Method Details

#before_templateObject



61
62
63
64
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 61

def before_template
  comment { "Before #{self.class.name}" }
  super
end

#convert_collection_hash_to_struct(collection, value_method:, text_method:) ⇒ Object



125
126
127
128
129
130
131
132
133
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 125

def convert_collection_hash_to_struct(collection, value_method:, text_method:)
  struct_constructor = Struct.new(value_method, text_method)
  collection.map do |item|
    struct = struct_constructor.new
    struct[value_method] = item[value_method]
    struct[text_method] = item[text_method]
    struct
  end
end

#default_attributesObject



67
68
69
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 67

def default_attributes
  {}
end

#find_as_child(rendered_element) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 89

def find_as_child(rendered_element)
  fragment = Nokogiri::HTML.fragment(rendered_element)
  element = fragment.children.find do |child|
    if child.is_a?(Nokogiri::XML::Comment)
      false
    else
      (child.is_a?(Nokogiri::XML::Text) && child.text.strip.present?) || !child.is_a?(Nokogiri::XML::Text)
    end
  end

  element
end

#icon(named, **options) ⇒ Object



117
118
119
120
121
122
123
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 117

def icon(named, **options)
  options = options.with_indifferent_access
  size = options.delete(:size)
  options = options.merge(width: size, height: size) if size

  svg(**LucideRails.default_options.merge(**options)) { LucideRails::IconProvider.icon(named).html_safe }
end

#item_disabled?(disabled, value) ⇒ Boolean

Returns:

  • (Boolean)


135
136
137
138
139
140
141
142
143
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 135

def item_disabled?(disabled, value)
  if disabled.is_a?(String)
    value == disabled
  elsif disabled.is_a?(Array)
    disabled.include?(value)
  else
    disabled
  end
end

#merge_default_attributes(attributes) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 45

def merge_default_attributes(attributes)
  @attributes = mix(default_attributes, attributes)
  @attributes = mix(@attributes, {
    data: {
      shadcn_phlexcomponents: self.class.name.demodulize.underscore.dasherize,
    },
  })

  @attributes[:class] = class_variants(class: @attributes[:class], **@class_variants&.compact)

  if @attributes[:class].blank?
    @attributes.delete(:class)
  end
end

#merged_as_child_attributes(element, component_attributes) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 102

def merged_as_child_attributes(element, component_attributes)
  element_attributes = nokogiri_attributes_to_hash(element)
  merged_attributes = mix(component_attributes, element_attributes)
  merged_attributes[:class] = TAILWIND_MERGER.merge("#{component_attributes[:class]} #{element_attributes[:class]}")

  # some components are divs that have role="button",
  # we should remove it if the child element is a button
  if component_attributes[:role].present? && component_attributes[:role].to_sym == :button && element.name == "button"
    merged_attributes.delete(:role)
  end

  merged_attributes
end

#nokogiri_attributes_to_hash(element) ⇒ Object



71
72
73
74
75
76
77
78
79
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 71

def nokogiri_attributes_to_hash(element)
  hash = {}

  element.attributes.each do |key, attr|
    hash[key] = attr.value
  end

  hash.transform_keys(&:to_sym)
end

#overlay(component) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 145

def overlay(component)
  div(
    style: { display: "none" },
    class: "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50 pointer-events-auto",
    aria: {
      hidden: true,
    },
    data: {
      state: "closed",
      "#{component}-target" => "overlay",
    },
  )
end

#sanitize_as_child(html) ⇒ Object



81
82
83
84
85
86
87
# File 'lib/shadcn_phlexcomponents/components/base.rb', line 81

def sanitize_as_child(html)
  sanitize(
    html,
    tags: SANITIZER_ALLOWED_TAGS,
    attributes: SANITIZER_ALLOWED_ATTRIBUTES,
  )
end