kiso 0.2.2.pre → 0.4.0.pre
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 +35 -1
- data/README.md +16 -3
- data/app/assets/tailwind/kiso/dialog.css +46 -0
- data/app/assets/tailwind/kiso/engine.css +6 -3
- data/app/assets/tailwind/kiso/input-otp.css +17 -0
- data/app/assets/tailwind/kiso/palettes/blue.css +65 -0
- data/app/assets/tailwind/kiso/palettes/green.css +65 -0
- data/app/assets/tailwind/kiso/palettes/orange.css +65 -0
- data/app/assets/tailwind/kiso/palettes/violet.css +65 -0
- data/app/assets/tailwind/kiso/palettes/zinc.css +65 -0
- data/app/assets/tailwind/kiso/slider.css +27 -0
- data/app/helpers/kiso/app_component_helper.rb +53 -0
- data/app/helpers/kiso/component_helper.rb +110 -24
- data/app/helpers/kiso/ui_context_helper.rb +59 -0
- data/app/javascript/controllers/kiso/alert_controller.js +33 -0
- data/app/javascript/controllers/kiso/dialog_controller.js +140 -0
- data/app/javascript/controllers/kiso/index.js +6 -0
- data/app/javascript/controllers/kiso/slider_controller.js +276 -0
- data/app/views/kiso/components/_alert.html.erb +19 -3
- data/app/views/kiso/components/_alert_dialog.html.erb +28 -0
- data/app/views/kiso/components/_app.html.erb +7 -0
- data/app/views/kiso/components/_aspect_ratio.html.erb +8 -0
- data/app/views/kiso/components/_avatar.html.erb +3 -3
- data/app/views/kiso/components/_breadcrumb.html.erb +1 -1
- data/app/views/kiso/components/_button.html.erb +31 -17
- data/app/views/kiso/components/_color_mode_button.html.erb +1 -1
- data/app/views/kiso/components/_color_mode_select.html.erb +4 -4
- data/app/views/kiso/components/_container.html.erb +7 -0
- data/app/views/kiso/components/_dashboard_sidebar.html.erb +1 -1
- data/app/views/kiso/components/_dialog.html.erb +11 -0
- data/app/views/kiso/components/_footer.html.erb +7 -0
- data/app/views/kiso/components/_header.html.erb +7 -0
- data/app/views/kiso/components/_main.html.erb +7 -0
- data/app/views/kiso/components/_page.html.erb +7 -0
- data/app/views/kiso/components/_page_body.html.erb +7 -0
- data/app/views/kiso/components/_page_card.html.erb +40 -0
- data/app/views/kiso/components/_page_grid.html.erb +7 -0
- data/app/views/kiso/components/_page_header.html.erb +38 -0
- data/app/views/kiso/components/_page_section.html.erb +11 -0
- data/app/views/kiso/components/_pagination.html.erb +1 -1
- data/app/views/kiso/components/_select_native.html.erb +3 -3
- data/app/views/kiso/components/_skeleton.html.erb +5 -0
- data/app/views/kiso/components/_slider.html.erb +42 -0
- data/app/views/kiso/components/_switch.html.erb +2 -2
- data/app/views/kiso/components/alert/_actions.html.erb +7 -0
- data/app/views/kiso/components/alert_dialog/_action.html.erb +8 -0
- data/app/views/kiso/components/alert_dialog/_cancel.html.erb +8 -0
- data/app/views/kiso/components/alert_dialog/_description.html.erb +8 -0
- data/app/views/kiso/components/alert_dialog/_footer.html.erb +7 -0
- data/app/views/kiso/components/alert_dialog/_header.html.erb +7 -0
- data/app/views/kiso/components/alert_dialog/_media.html.erb +7 -0
- data/app/views/kiso/components/alert_dialog/_title.html.erb +8 -0
- data/app/views/kiso/components/breadcrumb/_ellipsis.html.erb +1 -1
- data/app/views/kiso/components/combobox/_input.html.erb +1 -1
- data/app/views/kiso/components/combobox/_item.html.erb +2 -2
- data/app/views/kiso/components/combobox/_list.html.erb +2 -1
- data/app/views/kiso/components/command/_group.html.erb +2 -2
- data/app/views/kiso/components/command/_input.html.erb +3 -2
- data/app/views/kiso/components/command/_list.html.erb +2 -1
- data/app/views/kiso/components/dashboard_navbar/_toggle.html.erb +1 -1
- data/app/views/kiso/components/dashboard_sidebar/_collapse.html.erb +1 -1
- data/app/views/kiso/components/dashboard_sidebar/_toggle.html.erb +1 -1
- data/app/views/kiso/components/dialog/_body.html.erb +7 -0
- data/app/views/kiso/components/dialog/_close.html.erb +10 -0
- data/app/views/kiso/components/dialog/_description.html.erb +7 -0
- data/app/views/kiso/components/dialog/_footer.html.erb +7 -0
- data/app/views/kiso/components/dialog/_header.html.erb +7 -0
- data/app/views/kiso/components/dialog/_title.html.erb +7 -0
- data/app/views/kiso/components/empty/_actions.html.erb +7 -0
- data/app/views/kiso/components/nav/_item.html.erb +2 -2
- data/app/views/kiso/components/nav/_section.html.erb +5 -5
- data/app/views/kiso/components/page/_center.html.erb +7 -0
- data/app/views/kiso/components/page/_left.html.erb +7 -0
- data/app/views/kiso/components/page/_right.html.erb +7 -0
- data/app/views/kiso/components/page_card/_body.html.erb +7 -0
- data/app/views/kiso/components/page_card/_description.html.erb +7 -0
- data/app/views/kiso/components/page_card/_footer.html.erb +7 -0
- data/app/views/kiso/components/page_card/_header.html.erb +7 -0
- data/app/views/kiso/components/page_card/_icon.html.erb +7 -0
- data/app/views/kiso/components/page_card/_title.html.erb +7 -0
- data/app/views/kiso/components/page_header/_description.html.erb +7 -0
- data/app/views/kiso/components/page_header/_headline.html.erb +7 -0
- data/app/views/kiso/components/page_header/_links.html.erb +7 -0
- data/app/views/kiso/components/page_header/_title.html.erb +7 -0
- data/app/views/kiso/components/page_section/_body.html.erb +7 -0
- data/app/views/kiso/components/page_section/_description.html.erb +7 -0
- data/app/views/kiso/components/page_section/_header.html.erb +7 -0
- data/app/views/kiso/components/page_section/_headline.html.erb +7 -0
- data/app/views/kiso/components/page_section/_links.html.erb +7 -0
- data/app/views/kiso/components/page_section/_title.html.erb +7 -0
- data/app/views/kiso/components/page_section/_wrapper.html.erb +7 -0
- data/app/views/kiso/components/pagination/_ellipsis.html.erb +1 -1
- data/app/views/kiso/components/pagination/_next.html.erb +2 -2
- data/app/views/kiso/components/pagination/_previous.html.erb +2 -2
- data/app/views/kiso/components/select/_item.html.erb +2 -2
- data/config/locales/en.yml +33 -0
- data/lib/generators/kiso/component/USAGE +35 -0
- data/lib/generators/kiso/component/component_generator.rb +104 -0
- data/lib/generators/kiso/component/templates/partial.html.erb.tt +7 -0
- data/lib/generators/kiso/component/templates/sub_part_partial.html.erb.tt +7 -0
- data/lib/generators/kiso/component/templates/sub_part_theme.rb.tt +21 -0
- data/lib/generators/kiso/component/templates/theme.rb.tt +21 -0
- data/lib/kiso/configuration.rb +40 -0
- data/lib/kiso/engine.rb +105 -1
- data/lib/kiso/presets/rounded.rb +136 -0
- data/lib/kiso/presets/sharp.rb +178 -0
- data/lib/kiso/presets.rb +49 -0
- data/lib/kiso/theme_overrides.rb +5 -1
- data/lib/kiso/themes/alert.rb +24 -11
- data/lib/kiso/themes/alert_dialog.rb +78 -0
- data/lib/kiso/themes/aspect_ratio.rb +16 -0
- data/lib/kiso/themes/dashboard.rb +3 -3
- data/lib/kiso/themes/dialog.rb +57 -0
- data/lib/kiso/themes/empty.rb +6 -1
- data/lib/kiso/themes/input_otp.rb +2 -2
- data/lib/kiso/themes/layout.rb +69 -0
- data/lib/kiso/themes/page.rb +295 -0
- data/lib/kiso/themes/skeleton.rb +16 -0
- data/lib/kiso/themes/slider.rb +53 -0
- data/lib/kiso/version.rb +1 -1
- data/lib/kiso.rb +11 -0
- metadata +89 -1
data/lib/kiso/configuration.rb
CHANGED
|
@@ -23,9 +23,49 @@ module Kiso
|
|
|
23
23
|
# Applied once at boot by {ThemeOverrides.apply!}.
|
|
24
24
|
attr_reader :theme
|
|
25
25
|
|
|
26
|
+
# @return [Symbol] the active app theme directory name.
|
|
27
|
+
# Theme files are loaded from +app/themes/<name>/+. Defaults to
|
|
28
|
+
# +:default+, meaning +app/themes/default/+.
|
|
29
|
+
#
|
|
30
|
+
# @example Switch to a custom theme
|
|
31
|
+
# Kiso.configure do |config|
|
|
32
|
+
# config.app_theme = :modern
|
|
33
|
+
# end
|
|
34
|
+
attr_accessor :app_theme
|
|
35
|
+
|
|
26
36
|
def initialize
|
|
27
37
|
@icons = default_icons
|
|
28
38
|
@theme = {}
|
|
39
|
+
@app_theme = :default
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Resolves the active app theme directory path relative to the given root.
|
|
43
|
+
#
|
|
44
|
+
# @param app_root [Pathname] the Rails application root
|
|
45
|
+
# @return [Pathname] the active theme directory (e.g. +app/themes/default+)
|
|
46
|
+
def app_theme_path(app_root)
|
|
47
|
+
app_root.join("app/themes", app_theme.to_s)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Applies a pre-built style preset to all components.
|
|
51
|
+
# Presets populate +@theme+ before {ThemeOverrides.apply!} runs,
|
|
52
|
+
# so host-app overrides set after this call take priority.
|
|
53
|
+
#
|
|
54
|
+
# @param name [Symbol, String] the preset name (e.g. +:rounded+, +:sharp+)
|
|
55
|
+
# @raise [ArgumentError] if the preset does not exist
|
|
56
|
+
# @return [void]
|
|
57
|
+
#
|
|
58
|
+
# @example
|
|
59
|
+
# Kiso.configure do |config|
|
|
60
|
+
# config.apply_preset(:rounded)
|
|
61
|
+
# # Per-component overrides still work on top of the preset:
|
|
62
|
+
# config.theme[:button] = { base: "shadow-lg" }
|
|
63
|
+
# end
|
|
64
|
+
def apply_preset(name)
|
|
65
|
+
preset = Kiso::Presets.load(name)
|
|
66
|
+
preset.each do |component, overrides|
|
|
67
|
+
@theme[component] = (@theme[component] || {}).merge(overrides)
|
|
68
|
+
end
|
|
29
69
|
end
|
|
30
70
|
|
|
31
71
|
private
|
data/lib/kiso/engine.rb
CHANGED
|
@@ -10,6 +10,11 @@ module Kiso
|
|
|
10
10
|
class Engine < ::Rails::Engine
|
|
11
11
|
isolate_namespace Kiso
|
|
12
12
|
|
|
13
|
+
# Loads Kiso's locale files so host apps can override translations.
|
|
14
|
+
initializer "kiso.i18n" do
|
|
15
|
+
config.i18n.load_path += Dir[root.join("config/locales/**/*.yml")]
|
|
16
|
+
end
|
|
17
|
+
|
|
13
18
|
# Configures ClassVariants to use TailwindMerge for class deduplication.
|
|
14
19
|
# This ensures conflicting Tailwind utilities are resolved correctly
|
|
15
20
|
# when merging base, variant, and override classes.
|
|
@@ -27,10 +32,12 @@ module Kiso
|
|
|
27
32
|
Kiso::ThemeOverrides.apply!
|
|
28
33
|
end
|
|
29
34
|
|
|
30
|
-
# Makes {ComponentHelper} and {IconHelper} available in all views.
|
|
35
|
+
# Makes {ComponentHelper}, {AppComponentHelper}, and {IconHelper} available in all views.
|
|
31
36
|
initializer "kiso.helpers" do
|
|
32
37
|
ActiveSupport.on_load(:action_view) do
|
|
38
|
+
include Kiso::UiContextHelper
|
|
33
39
|
include Kiso::ComponentHelper
|
|
40
|
+
include Kiso::AppComponentHelper
|
|
34
41
|
include Kiso::IconHelper
|
|
35
42
|
include Kiso::ThemeHelper
|
|
36
43
|
end
|
|
@@ -96,6 +103,103 @@ module Kiso
|
|
|
96
103
|
end
|
|
97
104
|
end
|
|
98
105
|
|
|
106
|
+
# Watches lib/kiso/themes/ in development and reloads changed theme
|
|
107
|
+
# constants so you don't have to restart the server after every tweak.
|
|
108
|
+
# Uses Rails' built-in FileUpdateChecker (same mechanism as route reloading).
|
|
109
|
+
initializer "kiso.theme_reloading" do |app|
|
|
110
|
+
if Rails.env.development? || Rails.env.test?
|
|
111
|
+
theme_dir = root.join("lib/kiso/themes")
|
|
112
|
+
theme_files = Dir[theme_dir.join("*.rb")]
|
|
113
|
+
|
|
114
|
+
reloader = app.config.file_watcher.new(theme_files) do
|
|
115
|
+
# Suppress "already initialized constant" warnings during reload.
|
|
116
|
+
# Theme files assign to constants (Badge = ClassVariants.build(...))
|
|
117
|
+
# which is intentional — we want to replace the old instance.
|
|
118
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
|
119
|
+
begin
|
|
120
|
+
theme_files.each { |file| load file }
|
|
121
|
+
ensure
|
|
122
|
+
$VERBOSE = verbose
|
|
123
|
+
end
|
|
124
|
+
Kiso::ThemeOverrides.reset!
|
|
125
|
+
Kiso::ThemeOverrides.apply!
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
app.reloaders << reloader
|
|
129
|
+
|
|
130
|
+
ActiveSupport::Reloader.to_prepare do
|
|
131
|
+
reloader.execute_if_updated
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Loads the active app theme from +app/themes/<name>/+.
|
|
137
|
+
#
|
|
138
|
+
# Theme files define constants under the +AppThemes::+ namespace
|
|
139
|
+
# (e.g. +AppThemes::StatusBadge+) and are loaded via +require+ at
|
|
140
|
+
# boot. The active theme is determined by {Configuration#app_theme}
|
|
141
|
+
# (defaults to +:default+).
|
|
142
|
+
#
|
|
143
|
+
# No-op when +app/themes/+ doesn't exist. Raises a helpful error
|
|
144
|
+
# when the configured theme directory is missing.
|
|
145
|
+
initializer "kiso.app_themes", after: :load_config_initializers do |app|
|
|
146
|
+
themes_root = app.root.join("app/themes")
|
|
147
|
+
next unless themes_root.directory?
|
|
148
|
+
|
|
149
|
+
# Tell Zeitwerk to ignore app/themes/ — we manage loading ourselves.
|
|
150
|
+
# Rails auto-discovers app/* subdirectories and adds them to Zeitwerk,
|
|
151
|
+
# which would expect Default::StatusBadge (matching the directory name)
|
|
152
|
+
# instead of AppThemes::StatusBadge.
|
|
153
|
+
Rails.autoloaders.main.ignore(themes_root.to_s)
|
|
154
|
+
|
|
155
|
+
active_path = Kiso.config.app_theme_path(app.root)
|
|
156
|
+
|
|
157
|
+
unless active_path.directory?
|
|
158
|
+
available = Dir.children(themes_root.to_s)
|
|
159
|
+
.select { |d| File.directory?(themes_root.join(d)) }
|
|
160
|
+
.sort
|
|
161
|
+
|
|
162
|
+
msg = "Kiso app theme :#{Kiso.config.app_theme} not found. " \
|
|
163
|
+
"Expected directory: #{active_path}"
|
|
164
|
+
msg += if available.any?
|
|
165
|
+
"\nAvailable themes: #{available.map { |d| ":#{d}" }.join(", ")}"
|
|
166
|
+
else
|
|
167
|
+
"\nNo theme directories found in #{themes_root}. " \
|
|
168
|
+
"Run: bin/rails generate kiso:component your_component"
|
|
169
|
+
end
|
|
170
|
+
raise Kiso::Error, msg
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
Object.const_set(:AppThemes, Module.new) unless Object.const_defined?(:AppThemes)
|
|
174
|
+
|
|
175
|
+
Dir[active_path.join("**/*.rb")].sort.each { |file| load file }
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Watches the active app theme directory in development and reloads
|
|
179
|
+
# changed theme constants. Uses directory-based watching so new files
|
|
180
|
+
# added after boot are picked up automatically.
|
|
181
|
+
initializer "kiso.app_theme_reloading" do |app|
|
|
182
|
+
next unless Rails.env.development? || Rails.env.test?
|
|
183
|
+
|
|
184
|
+
active_path = Kiso.config.app_theme_path(app.root)
|
|
185
|
+
next unless active_path.directory?
|
|
186
|
+
|
|
187
|
+
reloader = app.config.file_watcher.new([], {active_path.to_s => ["rb"]}) do
|
|
188
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
|
189
|
+
begin
|
|
190
|
+
Dir[active_path.join("**/*.rb")].sort.each { |file| load file }
|
|
191
|
+
ensure
|
|
192
|
+
$VERBOSE = verbose
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
app.reloaders << reloader
|
|
197
|
+
|
|
198
|
+
ActiveSupport::Reloader.to_prepare do
|
|
199
|
+
reloader.execute_if_updated
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
99
203
|
# Registers Kiso's component previews with Lookbook when available.
|
|
100
204
|
initializer "kiso.lookbook", after: :load_config_initializers do
|
|
101
205
|
if defined?(Lookbook)
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kiso
|
|
4
|
+
module Presets
|
|
5
|
+
# Pill-shaped buttons, fully rounded badges, more rounded cards/inputs.
|
|
6
|
+
# Applies rounded-full where possible, rounded-2xl on containers.
|
|
7
|
+
#
|
|
8
|
+
# Components left unchanged:
|
|
9
|
+
# - Avatar, Switch, Slider, RadioGroup — already rounded-full
|
|
10
|
+
# - Checkbox — uses rounded-[4px] for checkmark alignment
|
|
11
|
+
# - Shared::CHECKABLE_ITEM — uses rounded-sm for menu items (structural)
|
|
12
|
+
ROUNDED = {
|
|
13
|
+
# Buttons: rounded-md → rounded-full (pill shape)
|
|
14
|
+
button: {
|
|
15
|
+
variants: {
|
|
16
|
+
size: {
|
|
17
|
+
xs: "rounded-full",
|
|
18
|
+
sm: "rounded-full",
|
|
19
|
+
md: "rounded-full",
|
|
20
|
+
lg: "rounded-full",
|
|
21
|
+
xl: "rounded-full"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
# Badges: already rounded-full — no change needed
|
|
27
|
+
|
|
28
|
+
# Card: rounded-xl → rounded-2xl
|
|
29
|
+
card: {base: "rounded-2xl"},
|
|
30
|
+
|
|
31
|
+
# StatsCard: rounded-xl → rounded-2xl
|
|
32
|
+
stats_card: {base: "rounded-2xl"},
|
|
33
|
+
|
|
34
|
+
# Input: rounded-md → rounded-full
|
|
35
|
+
input: {base: "rounded-full"},
|
|
36
|
+
|
|
37
|
+
# Textarea: rounded-md → rounded-xl (full doesn't work for multiline)
|
|
38
|
+
textarea: {base: "rounded-xl"},
|
|
39
|
+
|
|
40
|
+
# Select trigger: rounded-md → rounded-full
|
|
41
|
+
select_trigger: {base: "rounded-full"},
|
|
42
|
+
|
|
43
|
+
# Select content: rounded-md → rounded-xl
|
|
44
|
+
select_content: {base: "rounded-xl"},
|
|
45
|
+
|
|
46
|
+
# SelectNative: rounded-md → rounded-full
|
|
47
|
+
select_native: {base: "rounded-full"},
|
|
48
|
+
|
|
49
|
+
# InputGroup: rounded-md → rounded-full
|
|
50
|
+
input_group: {base: "rounded-full"},
|
|
51
|
+
|
|
52
|
+
# InputOTP slot: first:rounded-l-md last:rounded-r-md → first:rounded-l-xl last:rounded-r-xl
|
|
53
|
+
input_otp_slot: {base: "first:rounded-l-xl last:rounded-r-xl"},
|
|
54
|
+
|
|
55
|
+
# Toggle: rounded-md → rounded-full
|
|
56
|
+
toggle: {base: "rounded-full"},
|
|
57
|
+
|
|
58
|
+
# ToggleGroup: rounded-md → rounded-full
|
|
59
|
+
toggle_group: {base: "rounded-full"},
|
|
60
|
+
|
|
61
|
+
# ToggleGroupItem: first:rounded-l-md last:rounded-r-md → first:rounded-l-full last:rounded-r-full
|
|
62
|
+
toggle_group_item: {base: "first:rounded-l-full last:rounded-r-full"},
|
|
63
|
+
|
|
64
|
+
# Combobox input wrapper: rounded-md → rounded-full
|
|
65
|
+
combobox_input: {base: "rounded-full"},
|
|
66
|
+
|
|
67
|
+
# Combobox content: rounded-md → rounded-xl
|
|
68
|
+
combobox_content: {base: "rounded-xl"},
|
|
69
|
+
|
|
70
|
+
# Combobox chips (multi-select): rounded-md → rounded-xl
|
|
71
|
+
combobox_chips: {base: "rounded-xl"},
|
|
72
|
+
|
|
73
|
+
# Dialog content: rounded-lg → rounded-2xl
|
|
74
|
+
dialog_content: {base: "rounded-2xl"},
|
|
75
|
+
|
|
76
|
+
# AlertDialog content: rounded-lg → rounded-2xl
|
|
77
|
+
alert_dialog_content: {base: "rounded-2xl"},
|
|
78
|
+
|
|
79
|
+
# AlertDialog media: rounded-md → rounded-xl
|
|
80
|
+
alert_dialog_media: {base: "rounded-xl"},
|
|
81
|
+
|
|
82
|
+
# Alert: rounded-lg → rounded-2xl
|
|
83
|
+
alert: {base: "rounded-2xl"},
|
|
84
|
+
|
|
85
|
+
# Command: rounded-md → rounded-xl
|
|
86
|
+
command: {base: "rounded-xl"},
|
|
87
|
+
|
|
88
|
+
# CommandDialog content: rounded-lg → rounded-2xl
|
|
89
|
+
command_dialog_content: {base: "rounded-2xl"},
|
|
90
|
+
|
|
91
|
+
# Popover: rounded-md → rounded-xl
|
|
92
|
+
popover_content: {base: "rounded-xl"},
|
|
93
|
+
|
|
94
|
+
# DropdownMenu content: rounded-md → rounded-xl
|
|
95
|
+
dropdown_menu_content: {base: "rounded-xl"},
|
|
96
|
+
|
|
97
|
+
# DropdownMenu sub-content: rounded-md → rounded-xl
|
|
98
|
+
dropdown_menu_sub_content: {base: "rounded-xl"},
|
|
99
|
+
|
|
100
|
+
# Kbd: rounded-sm → rounded-md
|
|
101
|
+
kbd: {base: "rounded-md"},
|
|
102
|
+
|
|
103
|
+
# Skeleton: rounded-md → rounded-xl
|
|
104
|
+
skeleton: {base: "rounded-xl"},
|
|
105
|
+
|
|
106
|
+
# Pagination: rounded-md → rounded-full
|
|
107
|
+
pagination_link: {base: "rounded-full"},
|
|
108
|
+
pagination_previous: {base: "rounded-full"},
|
|
109
|
+
pagination_next: {base: "rounded-full"},
|
|
110
|
+
|
|
111
|
+
# Empty: rounded-lg → rounded-2xl
|
|
112
|
+
empty: {base: "rounded-2xl"},
|
|
113
|
+
|
|
114
|
+
# Empty media icon variant: rounded-lg → rounded-xl
|
|
115
|
+
empty_media: {
|
|
116
|
+
variants: {
|
|
117
|
+
variant: {
|
|
118
|
+
icon: "rounded-xl"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
# ColorModeButton: rounded-md → rounded-full
|
|
124
|
+
color_mode_button: {base: "rounded-full"},
|
|
125
|
+
|
|
126
|
+
# Nav section title: rounded-md → rounded-full
|
|
127
|
+
nav_section_title: {base: "rounded-full"},
|
|
128
|
+
|
|
129
|
+
# Nav item: rounded-md → rounded-full
|
|
130
|
+
nav_item: {base: "rounded-full"},
|
|
131
|
+
|
|
132
|
+
# Nav item badge: rounded-md → rounded-full
|
|
133
|
+
nav_item_badge: {base: "rounded-full"}
|
|
134
|
+
}.freeze
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kiso
|
|
4
|
+
module Presets
|
|
5
|
+
# No border-radius anywhere — geometric, brutalist aesthetic.
|
|
6
|
+
# Applies rounded-none to every component that has border-radius.
|
|
7
|
+
SHARP = {
|
|
8
|
+
# Buttons: rounded-md → rounded-none
|
|
9
|
+
button: {
|
|
10
|
+
variants: {
|
|
11
|
+
size: {
|
|
12
|
+
xs: "rounded-none",
|
|
13
|
+
sm: "rounded-none",
|
|
14
|
+
md: "rounded-none",
|
|
15
|
+
lg: "rounded-none",
|
|
16
|
+
xl: "rounded-none"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
# Badges: rounded-full → rounded-none
|
|
22
|
+
badge: {
|
|
23
|
+
variants: {
|
|
24
|
+
size: {
|
|
25
|
+
xs: "rounded-none",
|
|
26
|
+
sm: "rounded-none",
|
|
27
|
+
md: "rounded-none",
|
|
28
|
+
lg: "rounded-none",
|
|
29
|
+
xl: "rounded-none"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
# Card: rounded-xl → rounded-none
|
|
35
|
+
card: {base: "rounded-none"},
|
|
36
|
+
|
|
37
|
+
# StatsCard: rounded-xl → rounded-none
|
|
38
|
+
stats_card: {base: "rounded-none"},
|
|
39
|
+
|
|
40
|
+
# Input: rounded-md → rounded-none
|
|
41
|
+
input: {base: "rounded-none"},
|
|
42
|
+
|
|
43
|
+
# Textarea: rounded-md → rounded-none
|
|
44
|
+
textarea: {base: "rounded-none"},
|
|
45
|
+
|
|
46
|
+
# Select trigger: rounded-md → rounded-none
|
|
47
|
+
select_trigger: {base: "rounded-none"},
|
|
48
|
+
|
|
49
|
+
# Select content: rounded-md → rounded-none
|
|
50
|
+
select_content: {base: "rounded-none"},
|
|
51
|
+
|
|
52
|
+
# SelectNative: rounded-md → rounded-none
|
|
53
|
+
select_native: {base: "rounded-none"},
|
|
54
|
+
|
|
55
|
+
# InputGroup: rounded-md → rounded-none
|
|
56
|
+
input_group: {base: "rounded-none"},
|
|
57
|
+
|
|
58
|
+
# InputOTP slot: rounded-l-md/rounded-r-md → rounded-none
|
|
59
|
+
input_otp_slot: {base: "first:rounded-l-none last:rounded-r-none"},
|
|
60
|
+
|
|
61
|
+
# Toggle: rounded-md → rounded-none
|
|
62
|
+
toggle: {base: "rounded-none"},
|
|
63
|
+
|
|
64
|
+
# ToggleGroup: rounded-md → rounded-none
|
|
65
|
+
toggle_group: {base: "rounded-none"},
|
|
66
|
+
|
|
67
|
+
# ToggleGroupItem: rounded-l-md/rounded-r-md → rounded-none
|
|
68
|
+
toggle_group_item: {base: "first:rounded-l-none last:rounded-r-none"},
|
|
69
|
+
|
|
70
|
+
# Combobox input wrapper: rounded-md → rounded-none
|
|
71
|
+
combobox_input: {base: "rounded-none"},
|
|
72
|
+
|
|
73
|
+
# Combobox content: rounded-md → rounded-none
|
|
74
|
+
combobox_content: {base: "rounded-none"},
|
|
75
|
+
|
|
76
|
+
# Combobox chips (multi-select): rounded-md → rounded-none
|
|
77
|
+
combobox_chips: {base: "rounded-none"},
|
|
78
|
+
|
|
79
|
+
# Dialog content: rounded-lg → rounded-none
|
|
80
|
+
dialog_content: {base: "rounded-none"},
|
|
81
|
+
|
|
82
|
+
# AlertDialog content: rounded-lg → rounded-none
|
|
83
|
+
alert_dialog_content: {base: "rounded-none"},
|
|
84
|
+
|
|
85
|
+
# AlertDialog media: rounded-md → rounded-none
|
|
86
|
+
alert_dialog_media: {base: "rounded-none"},
|
|
87
|
+
|
|
88
|
+
# Alert: rounded-lg → rounded-none
|
|
89
|
+
alert: {base: "rounded-none"},
|
|
90
|
+
|
|
91
|
+
# Command: rounded-md → rounded-none
|
|
92
|
+
command: {base: "rounded-none"},
|
|
93
|
+
|
|
94
|
+
# CommandDialog content: rounded-lg → rounded-none
|
|
95
|
+
command_dialog_content: {base: "rounded-none"},
|
|
96
|
+
|
|
97
|
+
# DashboardNavbarToggle: rounded-md → rounded-none
|
|
98
|
+
dashboard_navbar_toggle: {base: "rounded-none"},
|
|
99
|
+
|
|
100
|
+
# DashboardSidebarCollapse: rounded-md → rounded-none
|
|
101
|
+
dashboard_sidebar_collapse: {base: "rounded-none"},
|
|
102
|
+
|
|
103
|
+
# DashboardSidebarToggle: rounded-md → rounded-none
|
|
104
|
+
dashboard_sidebar_toggle: {base: "rounded-none"},
|
|
105
|
+
|
|
106
|
+
# Popover: rounded-md → rounded-none
|
|
107
|
+
popover_content: {base: "rounded-none"},
|
|
108
|
+
|
|
109
|
+
# DropdownMenu content: rounded-md → rounded-none
|
|
110
|
+
dropdown_menu_content: {base: "rounded-none"},
|
|
111
|
+
|
|
112
|
+
# DropdownMenu sub-content: rounded-md → rounded-none
|
|
113
|
+
dropdown_menu_sub_content: {base: "rounded-none"},
|
|
114
|
+
|
|
115
|
+
# Kbd: rounded-sm → rounded-none
|
|
116
|
+
kbd: {base: "rounded-none"},
|
|
117
|
+
|
|
118
|
+
# Skeleton: rounded-md → rounded-none
|
|
119
|
+
skeleton: {base: "rounded-none"},
|
|
120
|
+
|
|
121
|
+
# Checkbox: rounded-[4px] → rounded-none
|
|
122
|
+
checkbox: {base: "rounded-none"},
|
|
123
|
+
|
|
124
|
+
# Avatar: rounded-full → rounded-none
|
|
125
|
+
avatar: {base: "rounded-none"},
|
|
126
|
+
avatar_badge: {base: "rounded-none"},
|
|
127
|
+
avatar_fallback: {base: "rounded-none"},
|
|
128
|
+
avatar_group_count: {base: "rounded-none"},
|
|
129
|
+
avatar_image: {base: "rounded-none"},
|
|
130
|
+
|
|
131
|
+
# Switch track: rounded-full → rounded-none
|
|
132
|
+
switch_track: {base: "rounded-none"},
|
|
133
|
+
switch_thumb: {base: "rounded-none"},
|
|
134
|
+
|
|
135
|
+
# Slider: rounded-full → rounded-none
|
|
136
|
+
slider_track: {base: "rounded-none"},
|
|
137
|
+
slider_thumb: {base: "rounded-none"},
|
|
138
|
+
|
|
139
|
+
# RadioGroup indicator: rounded-full → rounded-none
|
|
140
|
+
radio_group_item: {base: "rounded-none"},
|
|
141
|
+
|
|
142
|
+
# Pagination: rounded-md → rounded-none
|
|
143
|
+
pagination_link: {base: "rounded-none"},
|
|
144
|
+
pagination_previous: {base: "rounded-none"},
|
|
145
|
+
pagination_next: {base: "rounded-none"},
|
|
146
|
+
|
|
147
|
+
# Empty: rounded-lg → rounded-none
|
|
148
|
+
empty: {base: "rounded-none"},
|
|
149
|
+
|
|
150
|
+
# Empty media icon variant: rounded-lg → rounded-none
|
|
151
|
+
empty_media: {
|
|
152
|
+
variants: {
|
|
153
|
+
variant: {
|
|
154
|
+
icon: "rounded-none"
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
# Alert close: rounded-md → rounded-none
|
|
160
|
+
alert_close: {base: "rounded-none"},
|
|
161
|
+
|
|
162
|
+
# Dialog close: rounded-xs → rounded-none
|
|
163
|
+
dialog_close: {base: "rounded-none"},
|
|
164
|
+
|
|
165
|
+
# ColorModeButton: rounded-md → rounded-none
|
|
166
|
+
color_mode_button: {base: "rounded-none"},
|
|
167
|
+
|
|
168
|
+
# Nav section title: rounded-md → rounded-none
|
|
169
|
+
nav_section_title: {base: "rounded-none"},
|
|
170
|
+
|
|
171
|
+
# Nav item: rounded-md → rounded-none
|
|
172
|
+
nav_item: {base: "rounded-none"},
|
|
173
|
+
|
|
174
|
+
# Nav item badge: rounded-md → rounded-none
|
|
175
|
+
nav_item_badge: {base: "rounded-none"}
|
|
176
|
+
}.freeze
|
|
177
|
+
end
|
|
178
|
+
end
|
data/lib/kiso/presets.rb
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kiso
|
|
4
|
+
# Loads pre-built style presets that override ClassVariants for all
|
|
5
|
+
# components at boot time. Presets are monolithic, not composable —
|
|
6
|
+
# each preset is a complete, coherent set of overrides.
|
|
7
|
+
#
|
|
8
|
+
# @example Loading a preset
|
|
9
|
+
# Kiso.configure do |config|
|
|
10
|
+
# config.apply_preset(:rounded)
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# @see Configuration#apply_preset
|
|
14
|
+
module Presets
|
|
15
|
+
PRESET_DIR = File.expand_path("presets", __dir__).freeze
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
# Loads a preset by name and returns its override hash.
|
|
19
|
+
#
|
|
20
|
+
# @param name [Symbol, String] the preset name (e.g. +:rounded+, +:sharp+)
|
|
21
|
+
# @return [Hash{Symbol => Hash}] component overrides keyed by component name
|
|
22
|
+
# @raise [ArgumentError] if the preset does not exist
|
|
23
|
+
def load(name)
|
|
24
|
+
name = name.to_sym
|
|
25
|
+
file = File.join(PRESET_DIR, "#{name}.rb")
|
|
26
|
+
|
|
27
|
+
unless File.exist?(file)
|
|
28
|
+
available = available_presets
|
|
29
|
+
msg = "Unknown preset :#{name}."
|
|
30
|
+
msg += " Available presets: #{available.map { |p| ":#{p}" }.join(", ")}" if available.any?
|
|
31
|
+
raise ArgumentError, msg
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
require file
|
|
35
|
+
const_name = name.to_s.upcase
|
|
36
|
+
const_get(const_name)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Lists all available preset names.
|
|
40
|
+
#
|
|
41
|
+
# @return [Array<Symbol>] sorted list of preset names
|
|
42
|
+
def available_presets
|
|
43
|
+
Dir[File.join(PRESET_DIR, "*.rb")]
|
|
44
|
+
.map { |f| File.basename(f, ".rb").to_sym }
|
|
45
|
+
.sort
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/kiso/theme_overrides.rb
CHANGED
|
@@ -32,7 +32,11 @@ module Kiso
|
|
|
32
32
|
validate_keys!(overrides.keys)
|
|
33
33
|
|
|
34
34
|
overrides.each do |key, options|
|
|
35
|
-
|
|
35
|
+
# Extract ui: before passing to ClassVariants#merge (it doesn't
|
|
36
|
+
# understand ui:). The ui: values stay in config for runtime access
|
|
37
|
+
# by ComponentHelper#kiso_merge_ui_layers.
|
|
38
|
+
cv_options = options.except(:ui)
|
|
39
|
+
resolve_constant(key).merge(**cv_options) unless cv_options.empty?
|
|
36
40
|
end
|
|
37
41
|
|
|
38
42
|
@applied = true
|
data/lib/kiso/themes/alert.rb
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
module Kiso
|
|
2
2
|
module Themes
|
|
3
|
-
# Contextual alert banner with optional icon, title,
|
|
3
|
+
# Contextual alert banner with optional icon, title, description,
|
|
4
|
+
# actions, and close button.
|
|
4
5
|
#
|
|
5
|
-
# Uses
|
|
6
|
-
#
|
|
6
|
+
# Uses flexbox layout with an optional icon, a content wrapper, and
|
|
7
|
+
# an optional close button.
|
|
7
8
|
#
|
|
8
9
|
# @example
|
|
9
10
|
# Alert.render(color: :error, variant: :soft)
|
|
@@ -12,12 +13,9 @@ module Kiso
|
|
|
12
13
|
# - +color+ — :primary (default), :secondary, :success, :info, :warning, :error, :neutral
|
|
13
14
|
# - +variant+ — :solid, :outline, :soft (default), :subtle
|
|
14
15
|
#
|
|
15
|
-
# Sub-parts: {AlertTitle}, {AlertDescription}
|
|
16
|
+
# Sub-parts: {AlertWrapper}, {AlertTitle}, {AlertDescription}, {AlertActions}, {AlertClose}
|
|
16
17
|
Alert = ClassVariants.build(
|
|
17
|
-
base: "relative w-full rounded-lg
|
|
18
|
-
"grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] " \
|
|
19
|
-
"has-[>svg]:gap-x-3 gap-y-0.5 items-start " \
|
|
20
|
-
"[&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
|
|
18
|
+
base: "relative overflow-hidden w-full rounded-lg p-4 flex items-start gap-2.5 text-sm",
|
|
21
19
|
variants: {
|
|
22
20
|
variant: {
|
|
23
21
|
solid: "",
|
|
@@ -67,14 +65,29 @@ module Kiso
|
|
|
67
65
|
defaults: {color: :primary, variant: :soft}
|
|
68
66
|
)
|
|
69
67
|
|
|
70
|
-
#
|
|
68
|
+
# Flex wrapper for alert content (title, description, actions).
|
|
69
|
+
AlertWrapper = ClassVariants.build(
|
|
70
|
+
base: "min-w-0 flex-1 flex flex-col"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Alert title text.
|
|
71
74
|
AlertTitle = ClassVariants.build(
|
|
72
|
-
base: "
|
|
75
|
+
base: "line-clamp-1 min-h-4 font-medium tracking-tight"
|
|
73
76
|
)
|
|
74
77
|
|
|
75
78
|
# Alert body text. Inherits parent text color for contrast on colored backgrounds.
|
|
76
79
|
AlertDescription = ClassVariants.build(
|
|
77
|
-
base: "
|
|
80
|
+
base: "mt-1 first:mt-0 space-y-1 text-sm [&_p]:leading-relaxed"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Container for action buttons inside an alert.
|
|
84
|
+
AlertActions = ClassVariants.build(
|
|
85
|
+
base: "flex flex-wrap gap-1.5 shrink-0 mt-2.5"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Close button for dismissible alerts.
|
|
89
|
+
AlertClose = ClassVariants.build(
|
|
90
|
+
base: "shrink-0 -m-0.5 p-0.5 rounded-md opacity-70 hover:opacity-100 transition-opacity cursor-pointer"
|
|
78
91
|
)
|
|
79
92
|
end
|
|
80
93
|
end
|