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.
Files changed (177) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +590 -0
  3. data/LICENSE +49 -0
  4. data/README.md +542 -0
  5. data/app/assets/javascripts/shadcn/aria_relationships.js +88 -0
  6. data/app/assets/javascripts/shadcn/controllers/accordion_controller.js +241 -0
  7. data/app/assets/javascripts/shadcn/controllers/calendar_controller.js +98 -0
  8. data/app/assets/javascripts/shadcn/controllers/carousel_controller.js +305 -0
  9. data/app/assets/javascripts/shadcn/controllers/checked_state_controller.js +121 -0
  10. data/app/assets/javascripts/shadcn/controllers/combobox_controller.js +613 -0
  11. data/app/assets/javascripts/shadcn/controllers/command_controller.js +87 -0
  12. data/app/assets/javascripts/shadcn/controllers/dialog_controller.js +208 -0
  13. data/app/assets/javascripts/shadcn/controllers/hover_card_controller.js +145 -0
  14. data/app/assets/javascripts/shadcn/controllers/input_otp_controller.js +416 -0
  15. data/app/assets/javascripts/shadcn/controllers/menu_controller.js +286 -0
  16. data/app/assets/javascripts/shadcn/controllers/menubar_controller.js +430 -0
  17. data/app/assets/javascripts/shadcn/controllers/message_scroller_controller.js +37 -0
  18. data/app/assets/javascripts/shadcn/controllers/navigation_menu_controller.js +254 -0
  19. data/app/assets/javascripts/shadcn/controllers/popover_controller.js +117 -0
  20. data/app/assets/javascripts/shadcn/controllers/resizable_controller.js +256 -0
  21. data/app/assets/javascripts/shadcn/controllers/select_controller.js +491 -0
  22. data/app/assets/javascripts/shadcn/controllers/sidebar_controller.js +30 -0
  23. data/app/assets/javascripts/shadcn/controllers/slider_controller.js +74 -0
  24. data/app/assets/javascripts/shadcn/controllers/tabs_controller.js +146 -0
  25. data/app/assets/javascripts/shadcn/controllers/toast_controller.js +81 -0
  26. data/app/assets/javascripts/shadcn/controllers/toggle_controller.js +21 -0
  27. data/app/assets/javascripts/shadcn/controllers/toggle_group_controller.js +37 -0
  28. data/app/assets/javascripts/shadcn/controllers/tooltip_controller.js +123 -0
  29. data/app/assets/javascripts/shadcn/floating_position.js +660 -0
  30. data/app/assets/javascripts/shadcn/hide_after_exit.js +53 -0
  31. data/app/assets/javascripts/shadcn/index.js +65 -0
  32. data/app/assets/javascripts/shadcn/menu_popover.js +352 -0
  33. data/app/assets/javascripts/shadcn/package.json +17 -0
  34. data/app/assets/javascripts/shadcn/state_attrs.js +13 -0
  35. data/app/assets/stylesheets/shadcn/shadcn.css +766 -0
  36. data/app/assets/tailwind/shadcn_view_components/engine.css +11 -0
  37. data/app/components/shadcn/accordion.rb +121 -0
  38. data/app/components/shadcn/alert.rb +31 -0
  39. data/app/components/shadcn/alert_dialog.rb +165 -0
  40. data/app/components/shadcn/aspect_ratio.rb +34 -0
  41. data/app/components/shadcn/attachment.rb +86 -0
  42. data/app/components/shadcn/avatar.rb +55 -0
  43. data/app/components/shadcn/badge.rb +32 -0
  44. data/app/components/shadcn/base_component.rb +239 -0
  45. data/app/components/shadcn/breadcrumb.rb +70 -0
  46. data/app/components/shadcn/bubble.rb +48 -0
  47. data/app/components/shadcn/button.html.erb +1 -0
  48. data/app/components/shadcn/button.rb +41 -0
  49. data/app/components/shadcn/button_group.rb +41 -0
  50. data/app/components/shadcn/button_styled.rb +51 -0
  51. data/app/components/shadcn/calendar.rb +276 -0
  52. data/app/components/shadcn/card.rb +18 -0
  53. data/app/components/shadcn/carousel.rb +236 -0
  54. data/app/components/shadcn/chart.rb +57 -0
  55. data/app/components/shadcn/checkbox.rb +64 -0
  56. data/app/components/shadcn/collapsible.rb +25 -0
  57. data/app/components/shadcn/combobox.rb +552 -0
  58. data/app/components/shadcn/command.rb +149 -0
  59. data/app/components/shadcn/context_menu.rb +79 -0
  60. data/app/components/shadcn/dialog.rb +180 -0
  61. data/app/components/shadcn/direction_provider.rb +18 -0
  62. data/app/components/shadcn/drawer.rb +150 -0
  63. data/app/components/shadcn/dropdown_menu.rb +242 -0
  64. data/app/components/shadcn/empty.rb +40 -0
  65. data/app/components/shadcn/field.rb +106 -0
  66. data/app/components/shadcn/floating_position_options.rb +132 -0
  67. data/app/components/shadcn/form.rb +105 -0
  68. data/app/components/shadcn/hover_card.rb +66 -0
  69. data/app/components/shadcn/input.rb +13 -0
  70. data/app/components/shadcn/input_group/button.rb +48 -0
  71. data/app/components/shadcn/input_group.rb +51 -0
  72. data/app/components/shadcn/input_otp.rb +265 -0
  73. data/app/components/shadcn/item.rb +108 -0
  74. data/app/components/shadcn/kbd.rb +9 -0
  75. data/app/components/shadcn/label.rb +12 -0
  76. data/app/components/shadcn/marker.rb +37 -0
  77. data/app/components/shadcn/menubar.rb +110 -0
  78. data/app/components/shadcn/message.rb +29 -0
  79. data/app/components/shadcn/message_scroller.rb +52 -0
  80. data/app/components/shadcn/native_checked_state.rb +74 -0
  81. data/app/components/shadcn/native_select.rb +78 -0
  82. data/app/components/shadcn/navigation_menu.rb +122 -0
  83. data/app/components/shadcn/pagination.rb +160 -0
  84. data/app/components/shadcn/popover.rb +68 -0
  85. data/app/components/shadcn/preview_base.rb +107 -0
  86. data/app/components/shadcn/progress.rb +49 -0
  87. data/app/components/shadcn/radio_group.rb +74 -0
  88. data/app/components/shadcn/resizable.rb +77 -0
  89. data/app/components/shadcn/scroll_area.rb +59 -0
  90. data/app/components/shadcn/select.rb +356 -0
  91. data/app/components/shadcn/separator.rb +42 -0
  92. data/app/components/shadcn/sheet.rb +157 -0
  93. data/app/components/shadcn/sidebar.rb +332 -0
  94. data/app/components/shadcn/skeleton.rb +13 -0
  95. data/app/components/shadcn/slider.rb +279 -0
  96. data/app/components/shadcn/sonner.rb +30 -0
  97. data/app/components/shadcn/spinner.rb +32 -0
  98. data/app/components/shadcn/switch.rb +79 -0
  99. data/app/components/shadcn/table.rb +46 -0
  100. data/app/components/shadcn/tabs.rb +119 -0
  101. data/app/components/shadcn/textarea.rb +7 -0
  102. data/app/components/shadcn/toggle.rb +66 -0
  103. data/app/components/shadcn/toggle_group.rb +127 -0
  104. data/app/components/shadcn/tooltip.rb +74 -0
  105. data/config/importmap.rb +5 -0
  106. data/lib/generators/shadcn_view_components/install_generator.rb +182 -0
  107. data/lib/shadcn_view_components/classes.rb +89 -0
  108. data/lib/shadcn_view_components/component_naming.rb +21 -0
  109. data/lib/shadcn_view_components/contracts/calendar.rb +95 -0
  110. data/lib/shadcn_view_components/engine.rb +56 -0
  111. data/lib/shadcn_view_components/generated/contracts/accordion.rb +112 -0
  112. data/lib/shadcn_view_components/generated/contracts/alert-dialog.rb +300 -0
  113. data/lib/shadcn_view_components/generated/contracts/alert.rb +104 -0
  114. data/lib/shadcn_view_components/generated/contracts/aspect-ratio.rb +34 -0
  115. data/lib/shadcn_view_components/generated/contracts/attachment.rb +224 -0
  116. data/lib/shadcn_view_components/generated/contracts/avatar.rb +149 -0
  117. data/lib/shadcn_view_components/generated/contracts/badge.rb +39 -0
  118. data/lib/shadcn_view_components/generated/contracts/breadcrumb.rb +172 -0
  119. data/lib/shadcn_view_components/generated/contracts/bubble.rb +112 -0
  120. data/lib/shadcn_view_components/generated/contracts/button-group.rb +81 -0
  121. data/lib/shadcn_view_components/generated/contracts/button.rb +81 -0
  122. data/lib/shadcn_view_components/generated/contracts/card.rb +172 -0
  123. data/lib/shadcn_view_components/generated/contracts/carousel.rb +133 -0
  124. data/lib/shadcn_view_components/generated/contracts/chart.rb +109 -0
  125. data/lib/shadcn_view_components/generated/contracts/checkbox.rb +35 -0
  126. data/lib/shadcn_view_components/generated/contracts/collapsible.rb +89 -0
  127. data/lib/shadcn_view_components/generated/contracts/combobox.rb +368 -0
  128. data/lib/shadcn_view_components/generated/contracts/command.rb +222 -0
  129. data/lib/shadcn_view_components/generated/contracts/context-menu.rb +378 -0
  130. data/lib/shadcn_view_components/generated/contracts/dialog.rb +258 -0
  131. data/lib/shadcn_view_components/generated/contracts/direction.rb +34 -0
  132. data/lib/shadcn_view_components/generated/contracts/drawer.rb +280 -0
  133. data/lib/shadcn_view_components/generated/contracts/dropdown-menu.rb +380 -0
  134. data/lib/shadcn_view_components/generated/contracts/empty.rb +150 -0
  135. data/lib/shadcn_view_components/generated/contracts/field.rb +244 -0
  136. data/lib/shadcn_view_components/generated/contracts/form.rb +62 -0
  137. data/lib/shadcn_view_components/generated/contracts/hover-card.rb +90 -0
  138. data/lib/shadcn_view_components/generated/contracts/input-group.rb +155 -0
  139. data/lib/shadcn_view_components/generated/contracts/input-otp.rb +106 -0
  140. data/lib/shadcn_view_components/generated/contracts/input.rb +34 -0
  141. data/lib/shadcn_view_components/generated/contracts/item.rb +251 -0
  142. data/lib/shadcn_view_components/generated/contracts/kbd.rb +57 -0
  143. data/lib/shadcn_view_components/generated/contracts/label.rb +34 -0
  144. data/lib/shadcn_view_components/generated/contracts/marker.rb +82 -0
  145. data/lib/shadcn_view_components/generated/contracts/menubar.rb +394 -0
  146. data/lib/shadcn_view_components/generated/contracts/message-scroller.rb +149 -0
  147. data/lib/shadcn_view_components/generated/contracts/message.rb +149 -0
  148. data/lib/shadcn_view_components/generated/contracts/native-select.rb +82 -0
  149. data/lib/shadcn_view_components/generated/contracts/navigation-menu.rb +195 -0
  150. data/lib/shadcn_view_components/generated/contracts/pagination.rb +176 -0
  151. data/lib/shadcn_view_components/generated/contracts/popover.rb +159 -0
  152. data/lib/shadcn_view_components/generated/contracts/progress.rb +126 -0
  153. data/lib/shadcn_view_components/generated/contracts/radio-group.rb +58 -0
  154. data/lib/shadcn_view_components/generated/contracts/resizable.rb +85 -0
  155. data/lib/shadcn_view_components/generated/contracts/scroll-area.rb +59 -0
  156. data/lib/shadcn_view_components/generated/contracts/select.rb +245 -0
  157. data/lib/shadcn_view_components/generated/contracts/separator.rb +34 -0
  158. data/lib/shadcn_view_components/generated/contracts/sheet.rb +209 -0
  159. data/lib/shadcn_view_components/generated/contracts/sidebar.rb +558 -0
  160. data/lib/shadcn_view_components/generated/contracts/skeleton.rb +34 -0
  161. data/lib/shadcn_view_components/generated/contracts/slider.rb +38 -0
  162. data/lib/shadcn_view_components/generated/contracts/sonner.rb +36 -0
  163. data/lib/shadcn_view_components/generated/contracts/spinner.rb +34 -0
  164. data/lib/shadcn_view_components/generated/contracts/switch.rb +35 -0
  165. data/lib/shadcn_view_components/generated/contracts/table.rb +199 -0
  166. data/lib/shadcn_view_components/generated/contracts/tabs.rb +104 -0
  167. data/lib/shadcn_view_components/generated/contracts/textarea.rb +34 -0
  168. data/lib/shadcn_view_components/generated/contracts/toggle-group.rb +62 -0
  169. data/lib/shadcn_view_components/generated/contracts/toggle.rb +39 -0
  170. data/lib/shadcn_view_components/generated/contracts/tooltip.rb +116 -0
  171. data/lib/shadcn_view_components/numeric_property_validation.rb +124 -0
  172. data/lib/shadcn_view_components/property_contract_definitions.rb +92 -0
  173. data/lib/shadcn_view_components/property_contracts.rb +42 -0
  174. data/lib/shadcn_view_components/property_validation.rb +55 -0
  175. data/lib/shadcn_view_components/version.rb +6 -0
  176. data/lib/shadcn_view_components.rb +21 -0
  177. 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