shadcn_view_components 0.2.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +590 -0
- data/LICENSE +49 -0
- data/README.md +542 -0
- data/app/assets/javascripts/shadcn/aria_relationships.js +88 -0
- data/app/assets/javascripts/shadcn/controllers/accordion_controller.js +241 -0
- data/app/assets/javascripts/shadcn/controllers/calendar_controller.js +98 -0
- data/app/assets/javascripts/shadcn/controllers/carousel_controller.js +305 -0
- data/app/assets/javascripts/shadcn/controllers/checked_state_controller.js +121 -0
- data/app/assets/javascripts/shadcn/controllers/combobox_controller.js +613 -0
- data/app/assets/javascripts/shadcn/controllers/command_controller.js +87 -0
- data/app/assets/javascripts/shadcn/controllers/dialog_controller.js +208 -0
- data/app/assets/javascripts/shadcn/controllers/hover_card_controller.js +145 -0
- data/app/assets/javascripts/shadcn/controllers/input_otp_controller.js +416 -0
- data/app/assets/javascripts/shadcn/controllers/menu_controller.js +286 -0
- data/app/assets/javascripts/shadcn/controllers/menubar_controller.js +430 -0
- data/app/assets/javascripts/shadcn/controllers/message_scroller_controller.js +37 -0
- data/app/assets/javascripts/shadcn/controllers/navigation_menu_controller.js +254 -0
- data/app/assets/javascripts/shadcn/controllers/popover_controller.js +117 -0
- data/app/assets/javascripts/shadcn/controllers/resizable_controller.js +256 -0
- data/app/assets/javascripts/shadcn/controllers/select_controller.js +491 -0
- data/app/assets/javascripts/shadcn/controllers/sidebar_controller.js +30 -0
- data/app/assets/javascripts/shadcn/controllers/slider_controller.js +74 -0
- data/app/assets/javascripts/shadcn/controllers/tabs_controller.js +146 -0
- data/app/assets/javascripts/shadcn/controllers/toast_controller.js +81 -0
- data/app/assets/javascripts/shadcn/controllers/toggle_controller.js +21 -0
- data/app/assets/javascripts/shadcn/controllers/toggle_group_controller.js +37 -0
- data/app/assets/javascripts/shadcn/controllers/tooltip_controller.js +123 -0
- data/app/assets/javascripts/shadcn/floating_position.js +660 -0
- data/app/assets/javascripts/shadcn/hide_after_exit.js +53 -0
- data/app/assets/javascripts/shadcn/index.js +65 -0
- data/app/assets/javascripts/shadcn/menu_popover.js +352 -0
- data/app/assets/javascripts/shadcn/package.json +17 -0
- data/app/assets/javascripts/shadcn/state_attrs.js +13 -0
- data/app/assets/stylesheets/shadcn/shadcn.css +766 -0
- data/app/assets/tailwind/shadcn_view_components/engine.css +11 -0
- data/app/components/shadcn/accordion.rb +121 -0
- data/app/components/shadcn/alert.rb +31 -0
- data/app/components/shadcn/alert_dialog.rb +165 -0
- data/app/components/shadcn/aspect_ratio.rb +34 -0
- data/app/components/shadcn/attachment.rb +86 -0
- data/app/components/shadcn/avatar.rb +55 -0
- data/app/components/shadcn/badge.rb +32 -0
- data/app/components/shadcn/base_component.rb +239 -0
- data/app/components/shadcn/breadcrumb.rb +70 -0
- data/app/components/shadcn/bubble.rb +48 -0
- data/app/components/shadcn/button.html.erb +1 -0
- data/app/components/shadcn/button.rb +41 -0
- data/app/components/shadcn/button_group.rb +41 -0
- data/app/components/shadcn/button_styled.rb +51 -0
- data/app/components/shadcn/calendar.rb +276 -0
- data/app/components/shadcn/card.rb +18 -0
- data/app/components/shadcn/carousel.rb +236 -0
- data/app/components/shadcn/chart.rb +57 -0
- data/app/components/shadcn/checkbox.rb +64 -0
- data/app/components/shadcn/collapsible.rb +25 -0
- data/app/components/shadcn/combobox.rb +552 -0
- data/app/components/shadcn/command.rb +149 -0
- data/app/components/shadcn/context_menu.rb +79 -0
- data/app/components/shadcn/dialog.rb +180 -0
- data/app/components/shadcn/direction_provider.rb +18 -0
- data/app/components/shadcn/drawer.rb +150 -0
- data/app/components/shadcn/dropdown_menu.rb +242 -0
- data/app/components/shadcn/empty.rb +40 -0
- data/app/components/shadcn/field.rb +106 -0
- data/app/components/shadcn/floating_position_options.rb +132 -0
- data/app/components/shadcn/form.rb +105 -0
- data/app/components/shadcn/hover_card.rb +66 -0
- data/app/components/shadcn/input.rb +13 -0
- data/app/components/shadcn/input_group/button.rb +48 -0
- data/app/components/shadcn/input_group.rb +51 -0
- data/app/components/shadcn/input_otp.rb +265 -0
- data/app/components/shadcn/item.rb +108 -0
- data/app/components/shadcn/kbd.rb +9 -0
- data/app/components/shadcn/label.rb +12 -0
- data/app/components/shadcn/marker.rb +37 -0
- data/app/components/shadcn/menubar.rb +110 -0
- data/app/components/shadcn/message.rb +29 -0
- data/app/components/shadcn/message_scroller.rb +52 -0
- data/app/components/shadcn/native_checked_state.rb +74 -0
- data/app/components/shadcn/native_select.rb +78 -0
- data/app/components/shadcn/navigation_menu.rb +122 -0
- data/app/components/shadcn/pagination.rb +160 -0
- data/app/components/shadcn/popover.rb +68 -0
- data/app/components/shadcn/preview_base.rb +107 -0
- data/app/components/shadcn/progress.rb +49 -0
- data/app/components/shadcn/radio_group.rb +74 -0
- data/app/components/shadcn/resizable.rb +77 -0
- data/app/components/shadcn/scroll_area.rb +59 -0
- data/app/components/shadcn/select.rb +356 -0
- data/app/components/shadcn/separator.rb +42 -0
- data/app/components/shadcn/sheet.rb +157 -0
- data/app/components/shadcn/sidebar.rb +332 -0
- data/app/components/shadcn/skeleton.rb +13 -0
- data/app/components/shadcn/slider.rb +279 -0
- data/app/components/shadcn/sonner.rb +30 -0
- data/app/components/shadcn/spinner.rb +32 -0
- data/app/components/shadcn/switch.rb +79 -0
- data/app/components/shadcn/table.rb +46 -0
- data/app/components/shadcn/tabs.rb +119 -0
- data/app/components/shadcn/textarea.rb +7 -0
- data/app/components/shadcn/toggle.rb +66 -0
- data/app/components/shadcn/toggle_group.rb +127 -0
- data/app/components/shadcn/tooltip.rb +74 -0
- data/config/importmap.rb +5 -0
- data/lib/generators/shadcn_view_components/install_generator.rb +182 -0
- data/lib/shadcn_view_components/classes.rb +89 -0
- data/lib/shadcn_view_components/component_naming.rb +21 -0
- data/lib/shadcn_view_components/contracts/calendar.rb +95 -0
- data/lib/shadcn_view_components/engine.rb +56 -0
- data/lib/shadcn_view_components/generated/contracts/accordion.rb +112 -0
- data/lib/shadcn_view_components/generated/contracts/alert-dialog.rb +300 -0
- data/lib/shadcn_view_components/generated/contracts/alert.rb +104 -0
- data/lib/shadcn_view_components/generated/contracts/aspect-ratio.rb +34 -0
- data/lib/shadcn_view_components/generated/contracts/attachment.rb +224 -0
- data/lib/shadcn_view_components/generated/contracts/avatar.rb +149 -0
- data/lib/shadcn_view_components/generated/contracts/badge.rb +39 -0
- data/lib/shadcn_view_components/generated/contracts/breadcrumb.rb +172 -0
- data/lib/shadcn_view_components/generated/contracts/bubble.rb +112 -0
- data/lib/shadcn_view_components/generated/contracts/button-group.rb +81 -0
- data/lib/shadcn_view_components/generated/contracts/button.rb +81 -0
- data/lib/shadcn_view_components/generated/contracts/card.rb +172 -0
- data/lib/shadcn_view_components/generated/contracts/carousel.rb +133 -0
- data/lib/shadcn_view_components/generated/contracts/chart.rb +109 -0
- data/lib/shadcn_view_components/generated/contracts/checkbox.rb +35 -0
- data/lib/shadcn_view_components/generated/contracts/collapsible.rb +89 -0
- data/lib/shadcn_view_components/generated/contracts/combobox.rb +368 -0
- data/lib/shadcn_view_components/generated/contracts/command.rb +222 -0
- data/lib/shadcn_view_components/generated/contracts/context-menu.rb +378 -0
- data/lib/shadcn_view_components/generated/contracts/dialog.rb +258 -0
- data/lib/shadcn_view_components/generated/contracts/direction.rb +34 -0
- data/lib/shadcn_view_components/generated/contracts/drawer.rb +280 -0
- data/lib/shadcn_view_components/generated/contracts/dropdown-menu.rb +380 -0
- data/lib/shadcn_view_components/generated/contracts/empty.rb +150 -0
- data/lib/shadcn_view_components/generated/contracts/field.rb +244 -0
- data/lib/shadcn_view_components/generated/contracts/form.rb +62 -0
- data/lib/shadcn_view_components/generated/contracts/hover-card.rb +90 -0
- data/lib/shadcn_view_components/generated/contracts/input-group.rb +155 -0
- data/lib/shadcn_view_components/generated/contracts/input-otp.rb +106 -0
- data/lib/shadcn_view_components/generated/contracts/input.rb +34 -0
- data/lib/shadcn_view_components/generated/contracts/item.rb +251 -0
- data/lib/shadcn_view_components/generated/contracts/kbd.rb +57 -0
- data/lib/shadcn_view_components/generated/contracts/label.rb +34 -0
- data/lib/shadcn_view_components/generated/contracts/marker.rb +82 -0
- data/lib/shadcn_view_components/generated/contracts/menubar.rb +394 -0
- data/lib/shadcn_view_components/generated/contracts/message-scroller.rb +149 -0
- data/lib/shadcn_view_components/generated/contracts/message.rb +149 -0
- data/lib/shadcn_view_components/generated/contracts/native-select.rb +82 -0
- data/lib/shadcn_view_components/generated/contracts/navigation-menu.rb +195 -0
- data/lib/shadcn_view_components/generated/contracts/pagination.rb +176 -0
- data/lib/shadcn_view_components/generated/contracts/popover.rb +159 -0
- data/lib/shadcn_view_components/generated/contracts/progress.rb +126 -0
- data/lib/shadcn_view_components/generated/contracts/radio-group.rb +58 -0
- data/lib/shadcn_view_components/generated/contracts/resizable.rb +85 -0
- data/lib/shadcn_view_components/generated/contracts/scroll-area.rb +59 -0
- data/lib/shadcn_view_components/generated/contracts/select.rb +245 -0
- data/lib/shadcn_view_components/generated/contracts/separator.rb +34 -0
- data/lib/shadcn_view_components/generated/contracts/sheet.rb +209 -0
- data/lib/shadcn_view_components/generated/contracts/sidebar.rb +558 -0
- data/lib/shadcn_view_components/generated/contracts/skeleton.rb +34 -0
- data/lib/shadcn_view_components/generated/contracts/slider.rb +38 -0
- data/lib/shadcn_view_components/generated/contracts/sonner.rb +36 -0
- data/lib/shadcn_view_components/generated/contracts/spinner.rb +34 -0
- data/lib/shadcn_view_components/generated/contracts/switch.rb +35 -0
- data/lib/shadcn_view_components/generated/contracts/table.rb +199 -0
- data/lib/shadcn_view_components/generated/contracts/tabs.rb +104 -0
- data/lib/shadcn_view_components/generated/contracts/textarea.rb +34 -0
- data/lib/shadcn_view_components/generated/contracts/toggle-group.rb +62 -0
- data/lib/shadcn_view_components/generated/contracts/toggle.rb +39 -0
- data/lib/shadcn_view_components/generated/contracts/tooltip.rb +116 -0
- data/lib/shadcn_view_components/numeric_property_validation.rb +124 -0
- data/lib/shadcn_view_components/property_contract_definitions.rb +92 -0
- data/lib/shadcn_view_components/property_contracts.rb +42 -0
- data/lib/shadcn_view_components/property_validation.rb +55 -0
- data/lib/shadcn_view_components/version.rb +6 -0
- data/lib/shadcn_view_components.rb +21 -0
- metadata +446 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* shadcn_view_components: Tailwind CSS entry point for tailwindcss-rails. */
|
|
2
|
+
@import "../../stylesheets/shadcn/shadcn.css";
|
|
3
|
+
|
|
4
|
+
/* Generated and hand-maintained class contracts used at runtime. */
|
|
5
|
+
@source "../../../../lib/shadcn_view_components/generated/contracts/**/*.rb";
|
|
6
|
+
@source "../../../../lib/shadcn_view_components/contracts/**/*.rb";
|
|
7
|
+
|
|
8
|
+
/* Classes emitted directly by ViewComponents and distributed JavaScript. */
|
|
9
|
+
@source "../../../components/**/*.rb";
|
|
10
|
+
@source "../../../components/**/*.erb";
|
|
11
|
+
@source "../../javascripts/shadcn/**/*.js";
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Shadcn
|
|
5
|
+
class Accordion < BaseComponent
|
|
6
|
+
# ネイティブな details によるアコーディオン(JS無しで開閉可 — 05-stimulus-hotwire §3)。
|
|
7
|
+
# JS無効時フォールバック: Graceful(開閉・排他ともネイティブ要素で成立)。
|
|
8
|
+
# 単一排他は Item の name 属性で実現する(利用者が name: を渡す)。
|
|
9
|
+
# 開閉アニメーション(animate-accordion-down/up)は shadcn--accordion コントローラが
|
|
10
|
+
# data-state と高さ変数を同期して担う
|
|
11
|
+
CONTROLLER = "shadcn--accordion"
|
|
12
|
+
|
|
13
|
+
sig { params(args: T::Hash[Symbol, T.untyped]).void.checked(:never) }
|
|
14
|
+
def initialize(**args)
|
|
15
|
+
assign_accessibility_root_id(args, prefix: "accordion")
|
|
16
|
+
super
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
|
20
|
+
def contract_data_attributes
|
|
21
|
+
super.merge(controller: CONTROLLER)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class Item < BaseComponent
|
|
25
|
+
# 契約タグは AccordionPrimitive.Item。ネイティブな details として描く
|
|
26
|
+
sig { params(args: T::Hash[Symbol, T.untyped]).void.checked(:never) }
|
|
27
|
+
def initialize(**args)
|
|
28
|
+
assign_accessibility_root_id(args, prefix: "accordion-item")
|
|
29
|
+
super
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
sig { override.returns(String) }
|
|
33
|
+
def default_tag
|
|
34
|
+
"details"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Accordion ルート外で Item 単体を描画した場合も、開閉状態と
|
|
38
|
+
# ARIA参照を同期できるようにする。ルート内では親controllerが管理する。
|
|
39
|
+
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
|
40
|
+
def contract_data_attributes
|
|
41
|
+
super.merge(controller: Accordion::CONTROLLER)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Trigger < BaseComponent
|
|
46
|
+
# 契約ルートは AccordionPrimitive.Trigger。JS無しで開閉するため summary 要素として
|
|
47
|
+
# 描く。summary は details の直接子でなければ開閉機能しない(HTML仕様)ため、
|
|
48
|
+
# upstream の Header(h3)ラッパーは省略し、見出しセマンティクスは
|
|
49
|
+
# content に見出しを渡すことで表現する(summary は見出し内容を含めることができる)
|
|
50
|
+
sig { override.returns(String) }
|
|
51
|
+
def call
|
|
52
|
+
content_tag(:summary, **trigger_attributes) do
|
|
53
|
+
safe_join([content.presence, chevron_icons])
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
sig { returns(T::Hash[Symbol, T.untyped]) }
|
|
60
|
+
def trigger_attributes
|
|
61
|
+
attributes = @html_args.merge(class: self.class.classes(extra: @user_class))
|
|
62
|
+
merge_nested(attributes, :data, { slot: self.class.contract.const_get(:CLASSES_SLOT) })
|
|
63
|
+
merge_nested(attributes, :aria, { expanded: "false" })
|
|
64
|
+
attributes
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# base-nova は開閉で2つのアイコンを group-aria-expanded で切り替える
|
|
68
|
+
# (閉: ChevronDown / 開: ChevronUp)。両方を描き、表示は契約クラスに任せる
|
|
69
|
+
sig { returns(String) }
|
|
70
|
+
def chevron_icons
|
|
71
|
+
icon_slots = self.class.contract.const_get(:SLOTS)
|
|
72
|
+
.select { |slot| slot[:name] == "accordion-trigger-icon" }
|
|
73
|
+
safe_join(icon_slots.map do |slot|
|
|
74
|
+
content_tag(:span,
|
|
75
|
+
class: slot.dig(:static_attributes, :class),
|
|
76
|
+
data: { slot: "accordion-trigger-icon" },
|
|
77
|
+
"aria-hidden": "true") { chevron_svg }
|
|
78
|
+
end)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
sig { returns(String) }
|
|
82
|
+
def chevron_svg
|
|
83
|
+
content_tag(
|
|
84
|
+
:svg,
|
|
85
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
86
|
+
viewBox: "0 0 24 24",
|
|
87
|
+
fill: "none",
|
|
88
|
+
stroke: "currentColor",
|
|
89
|
+
"stroke-width": "2",
|
|
90
|
+
"stroke-linecap": "round",
|
|
91
|
+
"stroke-linejoin": "round",
|
|
92
|
+
width: "16",
|
|
93
|
+
height: "16",
|
|
94
|
+
class: "size-4"
|
|
95
|
+
) do
|
|
96
|
+
raw(%(<path d="m6 9 6 6 6-6"/>))
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class Content < BaseComponent
|
|
102
|
+
# upstream はルートに静的クラス(overflow-hidden / アニメーション)、
|
|
103
|
+
# 内側のdivに契約クラス(cn)を持つ二重構造。そのまま再現する
|
|
104
|
+
sig { override.returns(String) }
|
|
105
|
+
def call
|
|
106
|
+
attributes = @html_args.merge(class: root_static_class)
|
|
107
|
+
merge_nested(attributes, :data, { slot: contract_root_slot[:name] })
|
|
108
|
+
content_tag(tag, **attributes) do
|
|
109
|
+
content_tag(:div, class: self.class.classes(extra: @user_class)) { content }
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
private
|
|
114
|
+
|
|
115
|
+
sig { returns(T.nilable(String)) }
|
|
116
|
+
def root_static_class
|
|
117
|
+
T.cast(contract_root_slot.dig(:static_attributes, :class), T.nilable(String))
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Shadcn
|
|
5
|
+
class Alert < BaseComponent
|
|
6
|
+
sig do
|
|
7
|
+
params(
|
|
8
|
+
variant: T.any(Symbol, String),
|
|
9
|
+
args: T::Hash[Symbol, T.untyped]
|
|
10
|
+
).void.checked(:never)
|
|
11
|
+
end
|
|
12
|
+
def initialize(variant: ShadcnViewComponents::Contracts::Alert::DEFAULTS.fetch(:variant), **args)
|
|
13
|
+
@variant = T.let(normalize_option(:variant, variant), Symbol)
|
|
14
|
+
super(**args)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
sig { returns(Symbol) }
|
|
18
|
+
attr_reader :variant
|
|
19
|
+
|
|
20
|
+
sig { override.returns(T::Hash[Symbol, VariantOption]) }
|
|
21
|
+
def variant_options
|
|
22
|
+
{ variant: @variant }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class Title < BaseComponent
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class Description < BaseComponent
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Shadcn
|
|
5
|
+
# 確認ダイアログ(ネイティブ `<dialog>` + role="alertdialog")。
|
|
6
|
+
# EscはARIA Authoring Practicesのモーダルダイアログと同じく閉じる操作とし、
|
|
7
|
+
# ネイティブ <dialog> の cancel 動作に委ねる。
|
|
8
|
+
# JS無効時フォールバック: Readable(dialog と同じ)
|
|
9
|
+
class AlertDialog < BaseComponent
|
|
10
|
+
CONTROLLER = "shadcn--dialog"
|
|
11
|
+
|
|
12
|
+
sig { params(args: T::Hash[Symbol, T.untyped]).void.checked(:never) }
|
|
13
|
+
def initialize(**args)
|
|
14
|
+
assign_accessibility_root_id(args, prefix: "alert-dialog")
|
|
15
|
+
super
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
|
19
|
+
def contract_data_attributes
|
|
20
|
+
super.merge(controller: CONTROLLER)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Trigger < BaseComponent
|
|
24
|
+
include Shadcn::ButtonStyled
|
|
25
|
+
|
|
26
|
+
sig { override.returns(String) }
|
|
27
|
+
def default_tag
|
|
28
|
+
"button"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
|
32
|
+
def html_attributes
|
|
33
|
+
attributes = apply_button_styling(super)
|
|
34
|
+
attributes[:type] = "button" unless attributes.key?(:type)
|
|
35
|
+
merge_nested(attributes, :aria, { haspopup: "dialog", expanded: "false" })
|
|
36
|
+
merge_nested(attributes, :data, { action: "#{CONTROLLER}#show" })
|
|
37
|
+
attributes
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class Portal < BaseComponent
|
|
42
|
+
# upstream の Portal は子を body 末尾へ搬送するだけの機能要素。
|
|
43
|
+
# 本gemではラッパー div として実体化する(Dialog::Portal と同じ)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class Overlay < BaseComponent
|
|
47
|
+
# Dialog::Overlay と同じ扱い(::backdrop で代替)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class Content < BaseComponent
|
|
51
|
+
# 契約スロット構成: alert-dialog-content のみ(portal/overlayは契約外)。
|
|
52
|
+
# サイズ(default/sm)は data-size で表現する
|
|
53
|
+
sig { params(size: T.any(Symbol, String), args: T::Hash[Symbol, T.untyped]).void.checked(:never) }
|
|
54
|
+
def initialize(size: self.class.property_default(:size), **args)
|
|
55
|
+
@size = T.let(normalize_property(:size, size), String)
|
|
56
|
+
super(**args)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
sig { override.returns(String) }
|
|
60
|
+
def call
|
|
61
|
+
content_tag(:dialog, **content_attributes) { content }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
sig { returns(T::Hash[Symbol, T.untyped]) }
|
|
67
|
+
def content_attributes
|
|
68
|
+
attributes = @html_args.merge(
|
|
69
|
+
class: self.class.classes(extra: @user_class),
|
|
70
|
+
role: "alertdialog"
|
|
71
|
+
)
|
|
72
|
+
data = T.cast(attributes[:data], T.nilable(T::Hash[Symbol, T.untyped])) || {}
|
|
73
|
+
attributes[:data] = { slot: "alert-dialog-content", size: @size }.merge(data)
|
|
74
|
+
aria = T.cast(attributes[:aria], T.nilable(T::Hash[Symbol, T.untyped])) || {}
|
|
75
|
+
attributes[:aria] = { modal: "true" }.merge(aria)
|
|
76
|
+
attributes
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class Header < BaseComponent
|
|
81
|
+
# div
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
class Footer < BaseComponent
|
|
85
|
+
# div
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
class Title < BaseComponent
|
|
89
|
+
sig { override.returns(String) }
|
|
90
|
+
def default_tag
|
|
91
|
+
"h2"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
class Description < BaseComponent
|
|
96
|
+
sig { override.returns(String) }
|
|
97
|
+
def default_tag
|
|
98
|
+
"p"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class Media < BaseComponent
|
|
103
|
+
# div(アイコン等を含める領域)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Action/Cancel: upstream は Button を asChild で重ねる。本gemでは Button の
|
|
107
|
+
# 描画結果に data-slot を差し替えて出す(どちらも押下でダイアログを閉じる)
|
|
108
|
+
class Action < BaseComponent
|
|
109
|
+
sig do
|
|
110
|
+
params(
|
|
111
|
+
variant: T.any(Symbol, String),
|
|
112
|
+
size: T.any(Symbol, String),
|
|
113
|
+
args: T::Hash[Symbol, T.untyped]
|
|
114
|
+
).void.checked(:never)
|
|
115
|
+
end
|
|
116
|
+
def initialize(variant: :default, size: :default, **args)
|
|
117
|
+
@variant = T.let(ShadcnViewComponents::Classes.normalize_option(:button, :variant, variant), Symbol)
|
|
118
|
+
@size = T.let(ShadcnViewComponents::Classes.normalize_option(:button, :size, size), Symbol)
|
|
119
|
+
super(**args)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
sig { override.returns(String) }
|
|
123
|
+
def call
|
|
124
|
+
render(Button.new(variant: @variant, size: @size, type: "button", **button_attributes)) { content }
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
# Cancel 側は alert-dialog-cancel を上書きする
|
|
130
|
+
sig { returns(String) }
|
|
131
|
+
def slot_name
|
|
132
|
+
"alert-dialog-action"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
sig { returns(T::Hash[Symbol, T.untyped]) }
|
|
136
|
+
def button_attributes
|
|
137
|
+
data = T.cast(@html_args[:data], T.nilable(T::Hash[Symbol, T.untyped])) || {}
|
|
138
|
+
@html_args.merge(
|
|
139
|
+
data: { slot: slot_name, action: "#{CONTROLLER}#close" }.merge(data),
|
|
140
|
+
class: @user_class
|
|
141
|
+
)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
class Cancel < Action
|
|
146
|
+
sig do
|
|
147
|
+
params(
|
|
148
|
+
variant: T.any(Symbol, String),
|
|
149
|
+
size: T.any(Symbol, String),
|
|
150
|
+
args: T::Hash[Symbol, T.untyped]
|
|
151
|
+
).void.checked(:never)
|
|
152
|
+
end
|
|
153
|
+
def initialize(variant: :outline, size: :default, **args)
|
|
154
|
+
super
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
private
|
|
158
|
+
|
|
159
|
+
sig { override.returns(String) }
|
|
160
|
+
def slot_name
|
|
161
|
+
"alert-dialog-cancel"
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Shadcn
|
|
5
|
+
class AspectRatio < BaseComponent
|
|
6
|
+
# 契約タグは AspectRatioPrimitive.Root。ネイティブな div + CSS aspect-ratio で描画する
|
|
7
|
+
sig { override.returns(String) }
|
|
8
|
+
def default_tag
|
|
9
|
+
"div"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# upstream の ratio prop は style 経由でアスペクト比を指定する。ネイティブCSSで同等に再現
|
|
13
|
+
sig do
|
|
14
|
+
params(
|
|
15
|
+
ratio: T.nilable(T.any(Integer, Float, String)),
|
|
16
|
+
args: T::Hash[Symbol, T.untyped]
|
|
17
|
+
).void.checked(:never)
|
|
18
|
+
end
|
|
19
|
+
def initialize(ratio: self.class.property_default(:ratio), **args)
|
|
20
|
+
@ratio = T.let(normalize_property(:ratio, ratio), T.nilable(T.any(Integer, Float)))
|
|
21
|
+
super(**args)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
sig { returns(T.nilable(T.any(Integer, Float))) }
|
|
25
|
+
attr_reader :ratio
|
|
26
|
+
|
|
27
|
+
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
|
28
|
+
def html_attributes
|
|
29
|
+
attributes = super
|
|
30
|
+
merge_style(attributes, { aspect_ratio: @ratio.to_s }) if @ratio
|
|
31
|
+
attributes
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Shadcn
|
|
5
|
+
# 添付カード(Phase 4)。orientation/size のバリアントを持つ
|
|
6
|
+
class Attachment < BaseComponent
|
|
7
|
+
sig do
|
|
8
|
+
params(
|
|
9
|
+
orientation: T.any(Symbol, String),
|
|
10
|
+
size: T.any(Symbol, String),
|
|
11
|
+
args: T::Hash[Symbol, T.untyped]
|
|
12
|
+
).void.checked(:never)
|
|
13
|
+
end
|
|
14
|
+
def initialize(orientation: ShadcnViewComponents::Contracts::Attachment::DEFAULTS.fetch(:orientation),
|
|
15
|
+
size: ShadcnViewComponents::Contracts::Attachment::DEFAULTS.fetch(:size), **args)
|
|
16
|
+
@orientation = T.let(normalize_option(:orientation, orientation), Symbol)
|
|
17
|
+
@size = T.let(normalize_option(:size, size), Symbol)
|
|
18
|
+
super(**args)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
sig { override.returns(T::Hash[Symbol, VariantOption]) }
|
|
22
|
+
def variant_options
|
|
23
|
+
{ orientation: @orientation, size: @size }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class Group < BaseComponent
|
|
27
|
+
# div
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Media < BaseComponent
|
|
31
|
+
# サムネイル領域(variant: image/file)
|
|
32
|
+
sig { params(variant: T.any(Symbol, String), args: T::Hash[Symbol, T.untyped]).void.checked(:never) }
|
|
33
|
+
def initialize(variant: ShadcnViewComponents::Contracts::Attachment::Media::DEFAULTS.fetch(:variant), **args)
|
|
34
|
+
@variant = T.let(normalize_option(:variant, variant), Symbol)
|
|
35
|
+
super(**args)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
sig { override.returns(T::Hash[Symbol, VariantOption]) }
|
|
39
|
+
def variant_options
|
|
40
|
+
{ variant: @variant }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class Content < BaseComponent
|
|
45
|
+
# div
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class Title < BaseComponent
|
|
49
|
+
# div
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class Description < BaseComponent
|
|
53
|
+
# div
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class Actions < BaseComponent
|
|
57
|
+
# div
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class Action < BaseComponent
|
|
61
|
+
# button
|
|
62
|
+
sig { override.returns(String) }
|
|
63
|
+
def default_tag
|
|
64
|
+
"button"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
|
68
|
+
def html_attributes
|
|
69
|
+
super.tap { |attributes| attributes[:type] = "button" unless attributes.key?(:type) }
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class Trigger < BaseComponent
|
|
74
|
+
# button(削除等の個別操作)
|
|
75
|
+
sig { override.returns(String) }
|
|
76
|
+
def default_tag
|
|
77
|
+
"button"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
|
81
|
+
def html_attributes
|
|
82
|
+
super.tap { |attributes| attributes[:type] = "button" unless attributes.key?(:type) }
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Shadcn
|
|
5
|
+
class Avatar < BaseComponent
|
|
6
|
+
# 契約タグは AvatarPrimitive.Root。ネイティブな span として描画する
|
|
7
|
+
sig { override.returns(String) }
|
|
8
|
+
def default_tag
|
|
9
|
+
"span"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# upstream は size(default/sm/lg)を data-size 属性として描画する(クラスはdata-[size]セレクタで参照)
|
|
13
|
+
sig do
|
|
14
|
+
params(
|
|
15
|
+
size: T.any(Symbol, String),
|
|
16
|
+
args: T::Hash[Symbol, T.untyped]
|
|
17
|
+
).void.checked(:never)
|
|
18
|
+
end
|
|
19
|
+
def initialize(size: self.class.property_default(:size), **args)
|
|
20
|
+
@size = T.let(normalize_property(:size, size), String)
|
|
21
|
+
super(**args)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
sig { returns(String) }
|
|
25
|
+
attr_reader :size
|
|
26
|
+
|
|
27
|
+
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
|
28
|
+
def contract_data_attributes
|
|
29
|
+
super.merge(size: @size)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class Image < BaseComponent
|
|
33
|
+
# 契約タグは AvatarPrimitive.Image。ネイティブな img として描画する(void要素)
|
|
34
|
+
sig { override.returns(String) }
|
|
35
|
+
def default_tag
|
|
36
|
+
"img"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class Fallback < BaseComponent
|
|
41
|
+
sig { override.returns(String) }
|
|
42
|
+
def default_tag
|
|
43
|
+
"span"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class Badge < BaseComponent
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class Group < BaseComponent
|
|
51
|
+
class Count < BaseComponent
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Shadcn
|
|
5
|
+
class Badge < BaseComponent
|
|
6
|
+
# 省略時の既定値は契約の defaults から読む(リテラルで二重管理しない)
|
|
7
|
+
sig do
|
|
8
|
+
params(
|
|
9
|
+
variant: T.any(Symbol, String),
|
|
10
|
+
args: T::Hash[Symbol, T.untyped]
|
|
11
|
+
).void.checked(:never)
|
|
12
|
+
end
|
|
13
|
+
def initialize(variant: ShadcnViewComponents::Contracts::Badge::DEFAULTS.fetch(:variant), **args)
|
|
14
|
+
@variant = T.let(normalize_option(:variant, variant), Symbol)
|
|
15
|
+
super(**args)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
sig { returns(Symbol) }
|
|
19
|
+
attr_reader :variant
|
|
20
|
+
|
|
21
|
+
sig { override.returns(T::Hash[Symbol, VariantOption]) }
|
|
22
|
+
def variant_options
|
|
23
|
+
{ variant: @variant }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# upstream の動的属性(data-variant)は手書き側の責務として描画する
|
|
27
|
+
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
|
28
|
+
def contract_data_attributes
|
|
29
|
+
super.merge(variant: @variant)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|