shadcn-rails 0.2.0 → 0.2.1
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 +4 -4
- data/CHANGELOG.md +66 -2
- data/README.md +21 -8
- data/__mocks__/@floating-ui/dom.js +67 -0
- data/app/assets/javascripts/shadcn/controllers/combobox_controller.js +23 -2
- data/app/assets/javascripts/shadcn/controllers/context_menu_controller.js +4 -31
- data/app/assets/javascripts/shadcn/controllers/dropdown_controller.js +32 -41
- data/app/assets/javascripts/shadcn/controllers/hover_card_controller.js +29 -55
- data/app/assets/javascripts/shadcn/controllers/popover_controller.js +29 -54
- data/app/assets/javascripts/shadcn/controllers/select_controller.js +26 -8
- data/app/assets/javascripts/shadcn/controllers/tooltip_controller.js +28 -59
- data/app/assets/javascripts/shadcn/index.js +7 -1
- data/app/assets/javascripts/shadcn/utils/floating.js +179 -0
- data/app/assets/stylesheets/shadcn/base.css +32 -0
- data/app/components/shadcn/accordion_component.html.erb +8 -0
- data/app/components/shadcn/accordion_component.rb +6 -15
- data/app/components/shadcn/alert_component.html.erb +6 -0
- data/app/components/shadcn/alert_component.rb +0 -18
- data/app/components/shadcn/alert_dialog_component.html.erb +12 -0
- data/app/components/shadcn/alert_dialog_component.rb +7 -27
- data/app/components/shadcn/aspect_ratio_component.html.erb +7 -0
- data/app/components/shadcn/aspect_ratio_component.rb +4 -19
- data/app/components/shadcn/avatar_component.html.erb +20 -0
- data/app/components/shadcn/avatar_component.rb +8 -36
- data/app/components/shadcn/badge_component.html.erb +1 -0
- data/app/components/shadcn/badge_component.rb +0 -11
- data/app/components/shadcn/base_component.rb +15 -2
- data/app/components/shadcn/breadcrumb_component.html.erb +5 -0
- data/app/components/shadcn/breadcrumb_component.rb +6 -16
- data/app/components/shadcn/button_component.html.erb +18 -0
- data/app/components/shadcn/button_component.rb +1 -41
- data/app/components/shadcn/card_component.html.erb +8 -0
- data/app/components/shadcn/card_component.rb +2 -6
- data/app/components/shadcn/checkbox_component.html.erb +32 -0
- data/app/components/shadcn/checkbox_component.rb +4 -43
- data/app/components/shadcn/collapsible_component.html.erb +8 -0
- data/app/components/shadcn/collapsible_component.rb +6 -15
- data/app/components/shadcn/context_menu_component.html.erb +11 -0
- data/app/components/shadcn/context_menu_component.rb +6 -26
- data/app/components/shadcn/dialog_component.html.erb +14 -0
- data/app/components/shadcn/dialog_component.rb +8 -29
- data/app/components/shadcn/drawer_component.html.erb +12 -0
- data/app/components/shadcn/drawer_component.rb +7 -27
- data/app/components/shadcn/dropdown_menu_component.html.erb +14 -0
- data/app/components/shadcn/dropdown_menu_component.rb +9 -29
- data/app/components/shadcn/field_component.rb +7 -8
- data/app/components/shadcn/hover_card_component.html.erb +12 -0
- data/app/components/shadcn/hover_card_component.rb +7 -26
- data/app/components/shadcn/input_component.html.erb +18 -0
- data/app/components/shadcn/input_component.rb +2 -27
- data/app/components/shadcn/input_otp_component.rb +3 -3
- data/app/components/shadcn/kbd_component.html.erb +1 -0
- data/app/components/shadcn/kbd_component.rb +3 -10
- data/app/components/shadcn/label_component.html.erb +3 -0
- data/app/components/shadcn/label_component.rb +2 -18
- data/app/components/shadcn/menubar_component.html.erb +6 -0
- data/app/components/shadcn/menubar_component.rb +4 -15
- data/app/components/shadcn/native_select_component.html.erb +22 -0
- data/app/components/shadcn/native_select_component.rb +9 -39
- data/app/components/shadcn/navigation_menu_component.html.erb +6 -0
- data/app/components/shadcn/navigation_menu_component.rb +4 -15
- data/app/components/shadcn/pagination_component.html.erb +5 -0
- data/app/components/shadcn/pagination_component.rb +11 -15
- data/app/components/shadcn/popover_component.html.erb +15 -0
- data/app/components/shadcn/popover_component.rb +10 -30
- data/app/components/shadcn/progress_component.html.erb +13 -0
- data/app/components/shadcn/progress_component.rb +6 -26
- data/app/components/shadcn/radio_group_component.html.erb +8 -0
- data/app/components/shadcn/radio_group_component.rb +12 -26
- data/app/components/shadcn/scroll_area_component.html.erb +7 -0
- data/app/components/shadcn/scroll_area_component.rb +4 -16
- data/app/components/shadcn/select_component.html.erb +46 -0
- data/app/components/shadcn/select_component.rb +6 -80
- data/app/components/shadcn/separator_component.html.erb +5 -0
- data/app/components/shadcn/separator_component.rb +6 -14
- data/app/components/shadcn/sheet_component.html.erb +12 -0
- data/app/components/shadcn/sheet_component.rb +7 -27
- data/app/components/shadcn/sidebar_component.rb +2 -2
- data/app/components/shadcn/skeleton_component.html.erb +1 -0
- data/app/components/shadcn/skeleton_component.rb +4 -2
- data/app/components/shadcn/slider_component.html.erb +12 -0
- data/app/components/shadcn/slider_component.rb +2 -21
- data/app/components/shadcn/spinner_component.html.erb +18 -0
- data/app/components/shadcn/spinner_component.rb +2 -30
- data/app/components/shadcn/switch_component.html.erb +72 -0
- data/app/components/shadcn/switch_component.rb +4 -82
- data/app/components/shadcn/table_component.html.erb +9 -0
- data/app/components/shadcn/table_component.rb +2 -10
- data/app/components/shadcn/tabs_component.html.erb +8 -0
- data/app/components/shadcn/tabs_component.rb +4 -17
- data/app/components/shadcn/textarea_component.html.erb +13 -0
- data/app/components/shadcn/textarea_component.rb +6 -22
- data/app/components/shadcn/toast_component.html.erb +36 -0
- data/app/components/shadcn/toast_component.rb +6 -54
- data/app/components/shadcn/toggle_component.html.erb +12 -0
- data/app/components/shadcn/toggle_component.rb +6 -21
- data/app/components/shadcn/toggle_group_component.html.erb +14 -0
- data/app/components/shadcn/toggle_group_component.rb +6 -29
- data/app/components/shadcn/tooltip_component.html.erb +20 -0
- data/app/components/shadcn/tooltip_component.rb +13 -38
- data/lib/generators/shadcn/add/USAGE +24 -0
- data/lib/generators/shadcn/add/add_generator.rb +279 -0
- data/lib/generators/shadcn/install/USAGE +22 -0
- data/lib/generators/shadcn/install/install_generator.rb +8 -3
- data/lib/generators/shadcn/install/templates/initializer.rb.tt +7 -27
- data/lib/generators/shadcn/install/templates/shadcn.yml.tt +15 -31
- data/lib/shadcn/rails/version.rb +1 -1
- metadata +47 -45
- data/.dockerignore +0 -40
- data/CLAUDE.md +0 -612
- data/PROGRESS.md +0 -495
- data/Rakefile +0 -95
- data/__tests__/controllers/__snapshots__/calendar_controller.test.js.snap +0 -13
- data/__tests__/controllers/__snapshots__/popover_controller.test.js.snap +0 -46
- data/__tests__/controllers/__snapshots__/sheet_controller.test.js.snap +0 -111
- data/__tests__/controllers/__snapshots__/tabs_controller.test.js.snap +0 -27
- data/__tests__/controllers/accordion_controller.test.js +0 -904
- data/__tests__/controllers/calendar_controller.test.js +0 -1370
- data/__tests__/controllers/carousel_controller.test.js +0 -912
- data/__tests__/controllers/checkbox_controller.test.js +0 -454
- data/__tests__/controllers/collapsible_controller.test.js +0 -407
- data/__tests__/controllers/combobox_controller.test.js +0 -971
- data/__tests__/controllers/context_menu_controller.test.js +0 -905
- data/__tests__/controllers/date_picker_controller.test.js +0 -636
- data/__tests__/controllers/dialog_controller.test.js +0 -878
- data/__tests__/controllers/drawer_controller.test.js +0 -995
- data/__tests__/controllers/menubar_controller.test.js +0 -737
- data/__tests__/controllers/navigation_menu_controller.test.js +0 -599
- data/__tests__/controllers/popover_controller.test.js +0 -982
- data/__tests__/controllers/radio_group_controller.test.js +0 -640
- data/__tests__/controllers/resizable_controller.test.js +0 -680
- data/__tests__/controllers/select_controller.test.js +0 -678
- data/__tests__/controllers/sheet_controller.test.js +0 -986
- data/__tests__/controllers/slider_controller.test.js +0 -1036
- data/__tests__/controllers/switch_controller.test.js +0 -424
- data/__tests__/controllers/tabs_controller.test.js +0 -907
- data/__tests__/controllers/toggle_group_controller.test.js +0 -839
- data/__tests__/controllers/tooltip_controller.test.js +0 -808
- data/__tests__/helpers/stimulus-test-helper.js +0 -203
- data/babel.config.cjs +0 -5
- data/bin/bump +0 -321
- data/bin/console +0 -11
- data/bin/release +0 -205
- data/bin/setup +0 -8
- data/bin/test +0 -75
- data/jest.config.js +0 -19
- data/jest.setup.js +0 -8
- data/lib/generators/shadcn/component/component_generator.rb +0 -188
- data/lib/generators/shadcn/theme/theme_generator.rb +0 -128
- data/package-lock.json +0 -7438
- data/package.json +0 -71
- data/rollup.config.js +0 -29
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { Application } from "@hotwired/stimulus"
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Helper to set up Stimulus controller tests
|
|
5
|
-
* Creates a DOM element with the controller connected
|
|
6
|
-
*/
|
|
7
|
-
export function setupController(Controller, html, controllerName = 'test') {
|
|
8
|
-
const application = Application.start()
|
|
9
|
-
application.register(controllerName, Controller)
|
|
10
|
-
|
|
11
|
-
document.body.innerHTML = html
|
|
12
|
-
|
|
13
|
-
// Wait for Stimulus to connect the controller
|
|
14
|
-
return new Promise((resolve) => {
|
|
15
|
-
requestAnimationFrame(() => {
|
|
16
|
-
const element = document.querySelector(`[data-controller="${controllerName}"]`)
|
|
17
|
-
const controller = application.getControllerForElementAndIdentifier(element, controllerName)
|
|
18
|
-
resolve({ application, element, controller })
|
|
19
|
-
})
|
|
20
|
-
})
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Clean up after tests
|
|
25
|
-
*/
|
|
26
|
-
export function cleanupController(application) {
|
|
27
|
-
if (application) {
|
|
28
|
-
application.stop()
|
|
29
|
-
}
|
|
30
|
-
document.body.innerHTML = ''
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Simulate a click event on an element
|
|
35
|
-
*/
|
|
36
|
-
export function click(element) {
|
|
37
|
-
element.dispatchEvent(new MouseEvent('click', {
|
|
38
|
-
bubbles: true,
|
|
39
|
-
cancelable: true,
|
|
40
|
-
view: window
|
|
41
|
-
}))
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Wait for a specified number of milliseconds
|
|
46
|
-
*/
|
|
47
|
-
export function wait(ms) {
|
|
48
|
-
return new Promise(resolve => setTimeout(resolve, ms))
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Wait for an animation frame
|
|
53
|
-
*/
|
|
54
|
-
export function nextFrame() {
|
|
55
|
-
return new Promise(resolve => requestAnimationFrame(resolve))
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Simulate a keyboard event on an element
|
|
60
|
-
* @param {Element} element - Target element
|
|
61
|
-
* @param {string} key - Key name (e.g., 'ArrowDown', 'Enter', 'Escape')
|
|
62
|
-
* @param {Object} options - Additional options (shiftKey, ctrlKey, etc.)
|
|
63
|
-
*/
|
|
64
|
-
export function keydown(element, key, options = {}) {
|
|
65
|
-
element.dispatchEvent(new KeyboardEvent('keydown', {
|
|
66
|
-
key,
|
|
67
|
-
bubbles: true,
|
|
68
|
-
cancelable: true,
|
|
69
|
-
...options
|
|
70
|
-
}))
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Simulate a keyup event
|
|
75
|
-
*/
|
|
76
|
-
export function keyup(element, key, options = {}) {
|
|
77
|
-
element.dispatchEvent(new KeyboardEvent('keyup', {
|
|
78
|
-
key,
|
|
79
|
-
bubbles: true,
|
|
80
|
-
cancelable: true,
|
|
81
|
-
...options
|
|
82
|
-
}))
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Wait for a portal element to appear in the DOM
|
|
87
|
-
* @param {string} selector - CSS selector for the portal
|
|
88
|
-
* @param {boolean} shouldExist - Whether portal should exist (true) or not exist (false)
|
|
89
|
-
* @param {number} timeout - Maximum wait time in ms
|
|
90
|
-
*/
|
|
91
|
-
export async function waitForPortal(selector, shouldExist = true, timeout = 1000) {
|
|
92
|
-
const startTime = Date.now()
|
|
93
|
-
|
|
94
|
-
while (Date.now() - startTime < timeout) {
|
|
95
|
-
const element = document.querySelector(selector)
|
|
96
|
-
if (shouldExist && element) return element
|
|
97
|
-
if (!shouldExist && !element) return null
|
|
98
|
-
await wait(10)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
throw new Error(`Portal ${selector} ${shouldExist ? 'did not appear' : 'did not disappear'} within ${timeout}ms`)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Mock window.location for URL-related tests
|
|
106
|
-
* Uses jsdom's internal reconfigure or modifies location properties
|
|
107
|
-
* @param {string} url - The URL to mock
|
|
108
|
-
* @returns {Function} Cleanup function to restore original location
|
|
109
|
-
*/
|
|
110
|
-
export function mockLocation(url) {
|
|
111
|
-
// Store original href
|
|
112
|
-
const originalHref = window.location.href
|
|
113
|
-
|
|
114
|
-
// Use jsdom's reconfigure if available (available in newer jsdom)
|
|
115
|
-
if (typeof window._virtualConsole !== 'undefined' && window.location._setHref) {
|
|
116
|
-
window.location._setHref(url)
|
|
117
|
-
return () => {
|
|
118
|
-
if (window.location._setHref) {
|
|
119
|
-
window.location._setHref(originalHref)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Fallback: Use history API to change URL without navigation
|
|
125
|
-
const urlObj = new URL(url, window.location.origin)
|
|
126
|
-
window.history.replaceState({}, '', urlObj.href)
|
|
127
|
-
|
|
128
|
-
return () => {
|
|
129
|
-
window.history.replaceState({}, '', originalHref)
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Mock history.pushState and replaceState for URL sync tests
|
|
135
|
-
*/
|
|
136
|
-
export function mockHistory() {
|
|
137
|
-
const originalPushState = window.history.pushState
|
|
138
|
-
const originalReplaceState = window.history.replaceState
|
|
139
|
-
|
|
140
|
-
const calls = {
|
|
141
|
-
pushState: [],
|
|
142
|
-
replaceState: []
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
window.history.pushState = (state, title, url) => {
|
|
146
|
-
calls.pushState.push({ state, title, url })
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
window.history.replaceState = (state, title, url) => {
|
|
150
|
-
calls.replaceState.push({ state, title, url })
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
calls,
|
|
155
|
-
restore: () => {
|
|
156
|
-
window.history.pushState = originalPushState
|
|
157
|
-
window.history.replaceState = originalReplaceState
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Get all focusable elements within a container
|
|
164
|
-
* @param {Element} container - Container element
|
|
165
|
-
*/
|
|
166
|
-
export function getFocusableElements(container) {
|
|
167
|
-
return container.querySelectorAll(
|
|
168
|
-
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
169
|
-
)
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Dispatch a custom event
|
|
174
|
-
* @param {Element} element - Target element
|
|
175
|
-
* @param {string} eventName - Event name
|
|
176
|
-
* @param {Object} detail - Event detail object
|
|
177
|
-
*/
|
|
178
|
-
export function dispatchEvent(element, eventName, detail = {}) {
|
|
179
|
-
element.dispatchEvent(new CustomEvent(eventName, {
|
|
180
|
-
bubbles: true,
|
|
181
|
-
cancelable: true,
|
|
182
|
-
detail
|
|
183
|
-
}))
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Wait for controller to emit a specific event
|
|
188
|
-
* @param {Element} element - Element to listen on
|
|
189
|
-
* @param {string} eventName - Event name (e.g., 'shadcn--accordion:expand')
|
|
190
|
-
* @param {number} timeout - Maximum wait time
|
|
191
|
-
*/
|
|
192
|
-
export function waitForEvent(element, eventName, timeout = 1000) {
|
|
193
|
-
return new Promise((resolve, reject) => {
|
|
194
|
-
const timer = setTimeout(() => {
|
|
195
|
-
reject(new Error(`Event ${eventName} not received within ${timeout}ms`))
|
|
196
|
-
}, timeout)
|
|
197
|
-
|
|
198
|
-
element.addEventListener(eventName, (event) => {
|
|
199
|
-
clearTimeout(timer)
|
|
200
|
-
resolve(event)
|
|
201
|
-
}, { once: true })
|
|
202
|
-
})
|
|
203
|
-
}
|
data/babel.config.cjs
DELETED
data/bin/bump
DELETED
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Version bump script for shadcn-rails
|
|
5
|
-
# Updates version in both Ruby gem and npm package, commits, and tags
|
|
6
|
-
#
|
|
7
|
-
# Usage:
|
|
8
|
-
# bin/bump patch # Bump patch version, commit, and tag
|
|
9
|
-
# bin/bump minor # Bump minor version, commit, and tag
|
|
10
|
-
# bin/bump major # Bump major version, commit, and tag
|
|
11
|
-
# bin/bump 1.0.0 # Set specific version, commit, and tag
|
|
12
|
-
#
|
|
13
|
-
# Options:
|
|
14
|
-
# --no-commit Only update files, don't commit or tag
|
|
15
|
-
# --push Push commits and tags to remote after bumping
|
|
16
|
-
# --release Push and publish to RubyGems and npm
|
|
17
|
-
# --dry-run Show what would happen without making changes
|
|
18
|
-
|
|
19
|
-
require "json"
|
|
20
|
-
require "fileutils"
|
|
21
|
-
require "optparse"
|
|
22
|
-
|
|
23
|
-
VERSION_FILE = File.expand_path("../lib/shadcn/rails/version.rb", __dir__)
|
|
24
|
-
PACKAGE_JSON = File.expand_path("../package.json", __dir__)
|
|
25
|
-
CHANGELOG_FILE = File.expand_path("../CHANGELOG.md", __dir__)
|
|
26
|
-
|
|
27
|
-
class VersionBumper
|
|
28
|
-
def initialize(bump_type:, commit: true, push: false, release: false, dry_run: false)
|
|
29
|
-
@bump_type = bump_type
|
|
30
|
-
@commit = commit
|
|
31
|
-
@push = push
|
|
32
|
-
@release = release
|
|
33
|
-
@dry_run = dry_run
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def run
|
|
37
|
-
validate_environment
|
|
38
|
-
|
|
39
|
-
@old_version = current_version
|
|
40
|
-
@new_version = calculate_new_version
|
|
41
|
-
|
|
42
|
-
puts "\n📦 Bumping version: #{@old_version} → #{@new_version}\n\n"
|
|
43
|
-
|
|
44
|
-
update_files
|
|
45
|
-
commit_and_tag if @commit
|
|
46
|
-
push_to_remote if @push || @release
|
|
47
|
-
publish_packages if @release
|
|
48
|
-
|
|
49
|
-
print_summary
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
private
|
|
53
|
-
|
|
54
|
-
def validate_environment
|
|
55
|
-
# Check versions are in sync
|
|
56
|
-
ruby_ver = current_version
|
|
57
|
-
npm_ver = JSON.parse(File.read(PACKAGE_JSON))["version"]
|
|
58
|
-
|
|
59
|
-
if ruby_ver != npm_ver
|
|
60
|
-
error "Versions are out of sync!\n Ruby: #{ruby_ver}\n npm: #{npm_ver}"
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# Check for clean working directory if we're going to commit
|
|
64
|
-
if @commit && !@dry_run
|
|
65
|
-
status = `git status --porcelain`.strip
|
|
66
|
-
unless status.empty?
|
|
67
|
-
error "Working directory is not clean. Commit or stash changes first.\n\n#{status}"
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Check we're on a reasonable branch for releasing
|
|
72
|
-
if @release && !@dry_run
|
|
73
|
-
branch = `git branch --show-current`.strip
|
|
74
|
-
unless %w[main master].include?(branch)
|
|
75
|
-
puts "⚠️ Warning: You're on branch '#{branch}', not main/master"
|
|
76
|
-
print "Continue anyway? [y/N] "
|
|
77
|
-
response = $stdin.gets&.strip&.downcase
|
|
78
|
-
exit 1 unless response == "y"
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def current_version
|
|
84
|
-
content = File.read(VERSION_FILE)
|
|
85
|
-
content.match(/VERSION = "(.+?)"/)[1]
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def calculate_new_version
|
|
89
|
-
major, minor, patch = @old_version.split(".").map(&:to_i)
|
|
90
|
-
|
|
91
|
-
case @bump_type
|
|
92
|
-
when "major"
|
|
93
|
-
"#{major + 1}.0.0"
|
|
94
|
-
when "minor"
|
|
95
|
-
"#{major}.#{minor + 1}.0"
|
|
96
|
-
when "patch"
|
|
97
|
-
"#{major}.#{minor}.#{patch + 1}"
|
|
98
|
-
when /^\d+\.\d+\.\d+$/
|
|
99
|
-
@bump_type
|
|
100
|
-
else
|
|
101
|
-
error "Invalid version type: #{@bump_type}\nUse: patch, minor, major, or X.Y.Z"
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def update_files
|
|
106
|
-
step "Updating version files"
|
|
107
|
-
|
|
108
|
-
# Update Ruby version
|
|
109
|
-
if @dry_run
|
|
110
|
-
puts " [dry-run] Would update #{VERSION_FILE}"
|
|
111
|
-
else
|
|
112
|
-
content = File.read(VERSION_FILE)
|
|
113
|
-
new_content = content.gsub(/VERSION = ".+?"/, %(VERSION = "#{@new_version}"))
|
|
114
|
-
File.write(VERSION_FILE, new_content)
|
|
115
|
-
puts " ✓ Updated #{File.basename(VERSION_FILE)}"
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
# Update npm version
|
|
119
|
-
if @dry_run
|
|
120
|
-
puts " [dry-run] Would update #{PACKAGE_JSON}"
|
|
121
|
-
else
|
|
122
|
-
package = JSON.parse(File.read(PACKAGE_JSON))
|
|
123
|
-
package["version"] = @new_version
|
|
124
|
-
File.write(PACKAGE_JSON, JSON.pretty_generate(package) + "\n")
|
|
125
|
-
puts " ✓ Updated #{File.basename(PACKAGE_JSON)}"
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# Update changelog
|
|
129
|
-
if File.exist?(CHANGELOG_FILE)
|
|
130
|
-
if @dry_run
|
|
131
|
-
puts " [dry-run] Would update #{CHANGELOG_FILE}"
|
|
132
|
-
else
|
|
133
|
-
update_changelog
|
|
134
|
-
puts " ✓ Updated #{File.basename(CHANGELOG_FILE)}"
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def update_changelog
|
|
140
|
-
content = File.read(CHANGELOG_FILE)
|
|
141
|
-
today = Time.now.strftime("%Y-%m-%d")
|
|
142
|
-
|
|
143
|
-
# Replace [Unreleased] with new version
|
|
144
|
-
new_content = content.gsub(
|
|
145
|
-
/## \[Unreleased\]/,
|
|
146
|
-
"## [Unreleased]\n\n## [#{@new_version}] - #{today}"
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
# Update comparison links at bottom
|
|
150
|
-
new_content = new_content.gsub(
|
|
151
|
-
/\[Unreleased\]: (.+)\/compare\/v(.+?)\.\.\.HEAD/,
|
|
152
|
-
"[Unreleased]: \\1/compare/v#{@new_version}...HEAD\n[#{@new_version}]: \\1/compare/v\\2...v#{@new_version}"
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
File.write(CHANGELOG_FILE, new_content)
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def commit_and_tag
|
|
159
|
-
step "Committing and tagging"
|
|
160
|
-
|
|
161
|
-
tag = "v#{@new_version}"
|
|
162
|
-
commit_message = "Bump version to #{@new_version}"
|
|
163
|
-
|
|
164
|
-
if @dry_run
|
|
165
|
-
puts " [dry-run] Would run: git add -A"
|
|
166
|
-
puts " [dry-run] Would run: git commit -m '#{commit_message}'"
|
|
167
|
-
puts " [dry-run] Would run: git tag #{tag}"
|
|
168
|
-
else
|
|
169
|
-
system("git add -A")
|
|
170
|
-
system("git commit -m '#{commit_message}'")
|
|
171
|
-
system("git tag #{tag}")
|
|
172
|
-
puts " ✓ Created commit and tag #{tag}"
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def push_to_remote
|
|
177
|
-
step "Pushing to remote"
|
|
178
|
-
|
|
179
|
-
if @dry_run
|
|
180
|
-
puts " [dry-run] Would run: git push"
|
|
181
|
-
puts " [dry-run] Would run: git push --tags"
|
|
182
|
-
else
|
|
183
|
-
success = system("git push && git push --tags")
|
|
184
|
-
if success
|
|
185
|
-
puts " ✓ Pushed commits and tags"
|
|
186
|
-
else
|
|
187
|
-
error "Failed to push to remote"
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
def publish_packages
|
|
193
|
-
step "Publishing packages"
|
|
194
|
-
|
|
195
|
-
if @dry_run
|
|
196
|
-
puts " [dry-run] Would run: bin/release"
|
|
197
|
-
return
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
# Build first
|
|
201
|
-
puts " Building packages..."
|
|
202
|
-
system("npm run build") || error("npm build failed")
|
|
203
|
-
system("gem build shadcn-rails.gemspec") || error("gem build failed")
|
|
204
|
-
|
|
205
|
-
gem_file = "shadcn-rails-#{@new_version}.gem"
|
|
206
|
-
|
|
207
|
-
# Publish to RubyGems
|
|
208
|
-
puts " Publishing to RubyGems..."
|
|
209
|
-
unless system("gem push #{gem_file}")
|
|
210
|
-
puts " ⚠️ Failed to publish gem (may need: gem signin)"
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
# Publish to npm
|
|
214
|
-
puts " Publishing to npm..."
|
|
215
|
-
unless system("npm publish")
|
|
216
|
-
puts " ⚠️ Failed to publish to npm (may need: npm login)"
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
# Clean up
|
|
220
|
-
File.delete(gem_file) if File.exist?(gem_file)
|
|
221
|
-
|
|
222
|
-
puts " ✓ Published packages"
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def print_summary
|
|
226
|
-
puts "\n" + "=" * 50
|
|
227
|
-
puts "✅ Version bumped to #{@new_version}"
|
|
228
|
-
puts "=" * 50
|
|
229
|
-
|
|
230
|
-
unless @commit
|
|
231
|
-
puts "\nFiles updated. Next steps:"
|
|
232
|
-
puts " git add -A"
|
|
233
|
-
puts " git commit -m 'Bump version to #{@new_version}'"
|
|
234
|
-
puts " git tag v#{@new_version}"
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
if @commit && !@push && !@release
|
|
238
|
-
puts "\nCommitted and tagged. To publish:"
|
|
239
|
-
puts " git push && git push --tags"
|
|
240
|
-
puts " bin/release"
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
if @push && !@release
|
|
244
|
-
puts "\nPushed to remote. To publish packages:"
|
|
245
|
-
puts " bin/release"
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
if @release
|
|
249
|
-
puts "\nRelease complete! 🎉"
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
def step(message)
|
|
254
|
-
puts "→ #{message}"
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
def error(message)
|
|
258
|
-
puts "\n❌ Error: #{message}"
|
|
259
|
-
exit 1
|
|
260
|
-
end
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
# Parse command line options
|
|
264
|
-
options = {
|
|
265
|
-
commit: true,
|
|
266
|
-
push: false,
|
|
267
|
-
release: false,
|
|
268
|
-
dry_run: false
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
parser = OptionParser.new do |opts|
|
|
272
|
-
opts.banner = "Usage: bin/bump <patch|minor|major|X.Y.Z> [options]"
|
|
273
|
-
|
|
274
|
-
opts.on("--no-commit", "Only update files, don't commit or tag") do
|
|
275
|
-
options[:commit] = false
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
opts.on("--push", "Push commits and tags to remote") do
|
|
279
|
-
options[:push] = true
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
opts.on("--release", "Push and publish to RubyGems and npm") do
|
|
283
|
-
options[:release] = true
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
opts.on("--dry-run", "Show what would happen without making changes") do
|
|
287
|
-
options[:dry_run] = true
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
opts.on("-h", "--help", "Show this help message") do
|
|
291
|
-
puts opts
|
|
292
|
-
puts "\nExamples:"
|
|
293
|
-
puts " bin/bump patch # Bump 0.1.0 → 0.1.1, commit, tag"
|
|
294
|
-
puts " bin/bump minor --push # Bump 0.1.0 → 0.2.0, commit, tag, push"
|
|
295
|
-
puts " bin/bump major --release # Bump 0.1.0 → 1.0.0, commit, tag, push, publish"
|
|
296
|
-
puts " bin/bump 1.0.0 --no-commit # Set to 1.0.0, only update files"
|
|
297
|
-
puts " bin/bump patch --dry-run # Preview what would happen"
|
|
298
|
-
exit 0
|
|
299
|
-
end
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
parser.parse!
|
|
303
|
-
|
|
304
|
-
if ARGV.empty?
|
|
305
|
-
# Show current version and help
|
|
306
|
-
ruby_version = File.read(VERSION_FILE).match(/VERSION = "(.+?)"/)[1]
|
|
307
|
-
puts "Current version: #{ruby_version}"
|
|
308
|
-
puts ""
|
|
309
|
-
puts parser
|
|
310
|
-
exit 1
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
bump_type = ARGV[0]
|
|
314
|
-
|
|
315
|
-
VersionBumper.new(
|
|
316
|
-
bump_type: bump_type,
|
|
317
|
-
commit: options[:commit],
|
|
318
|
-
push: options[:push],
|
|
319
|
-
release: options[:release],
|
|
320
|
-
dry_run: options[:dry_run]
|
|
321
|
-
).run
|
data/bin/console
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require "bundler/setup"
|
|
5
|
-
require "shadcn/rails"
|
|
6
|
-
|
|
7
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
-
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
-
|
|
10
|
-
require "irb"
|
|
11
|
-
IRB.start(__FILE__)
|