Shadwire
Componentes

Calendar

Uma grade de mês construída no cliente: navegação, seleção simples ou por intervalo e teclado.

Instalação

O Shadwire segue o modelo open-code do shadcn/ui: o código-fonte do componente é copiado para a sua aplicação e passa a ser seu. Instale com a CLI:

shadwire add calendar --yes

O item calendar do registry instala estes arquivos:

  • app/components/ui_component.rb
  • app/components/ui/calendar_component.rb
  • app/helpers/ui/calendar_helper.rb
  • app/javascript/controllers/ui_calendar_controller.js
  • vendor/shadwire/shadwire.css

Este componente usa Stimulus: a aplicação precisa de importmap-rails e stimulus-rails com carregamento automático de controllers.

Ainda não instalou a CLI? gem install shadwire e depois shadwire init.

Uso

O servidor renderiza só o esqueleto; o controller ui-calendar monta os dias, então trocar de mês não custa uma requisição. A data escolhida vai para um input[type=hidden] — o calendário funciona dentro de um form_with como qualquer outro campo. Para um campo que abre o calendário em um popover, veja Date Picker.

<%= ui_calendar(selected: Date.current, name: "date", class: "border") %>

<%# Intervalo: duas datas, dois inputs, dois meses. %>
<%= ui_calendar(
      mode: :range,
      selected: Date.current..(Date.current + 7),
      number_of_months: 2,
      name: "trip[starts_on]",

Exemplos

Padrão

Mês atual com o dia de hoje selecionado. Setas percorrem os dias, Home/End vão às pontas da semana e PageUp/PageDown trocam de mês.

<%# Inline o calendário desenha o próprio quadro; dentro de um popover é o
    popover que faz esse papel, por isso a borda fica a cargo de quem usa. %>
<%= ui_calendar(selected: Date.today, name: "date", class: "border") %>

Intervalo

mode: :range grava duas datas; passar o mouse depois do primeiro clique prevê o intervalo. number_of_months: 2 mostra dois meses lado a lado.

<%= ui_calendar(
      mode: :range,
      selected: Date.current..(Date.current + 12),
      number_of_months: 2,
      name: "trip[starts_on]",
      end_name: "trip[ends_on]",
      class: "border"
    ) %>

Legenda com selects

caption_layout: :dropdown troca o nome do mês por selects de mês e ano — o caminho curto para anos distantes.

<%# `min:`/`max:` desabilitam os dias fora da faixa e delimitam o select de ano. %>
<%= ui_calendar(
      caption_layout: :dropdown,
      name: "born_on",
      min: Date.new(1930, 1, 1),
      max: Date.current,
      class: "border"
    ) %>

Referência da API

Datas aceitam Date ou string YYYY-MM-DD. Como todo componente, aceita também class / class_name e **attrs.

Argumento Padrão Descrição
mode :single :range seleciona um intervalo; o segundo clique fecha a ponta.
selected A data escolhida. Em :range aceita um intervalo (Date..Date).
from, to As pontas do intervalo, quando prefere passá-las separadas.
name, end_name Os inputs escondidos. name é a data (ou o início); end_name, o fim.
month seleção, senão hoje Primeiro mês visível.
min, max Desabilitam os dias fora da faixa e delimitam o select de ano.
number_of_months 1 Meses consecutivos lado a lado. 2 é o par usual para intervalos.
caption_layout :label :dropdown troca o nome do mês por selects de mês e ano (só com um mês).
year_range −100…+10 anos Anos do select. min:/max: têm precedência quando informados.
dir :rtl espelha a grade, as setas de navegação e as teclas ←/→.
week_start 0 Primeiro dia da semana: 0 domingo, 1 segunda.
month_names, day_names pt-BR Rótulos da legenda e do cabeçalho, ex.: I18n.t("date.month_names").compact.

Eventos: ui-calendar:change a cada escolha e ui-calendar:connect quando o calendário monta, ambos com detail: { date, from, to }. No sentido inverso, ui-calendar#setDate leva o calendário até uma data vinda de fora.