kiso 0.1.0.pre → 0.2.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 +36 -2
- data/README.md +67 -27
- data/Rakefile +8 -0
- data/app/assets/tailwind/kiso/checkbox.css +18 -0
- data/app/assets/tailwind/kiso/color-mode.css +9 -0
- data/app/assets/tailwind/kiso/dashboard.css +194 -0
- data/app/assets/tailwind/kiso/engine.css +117 -0
- data/app/assets/tailwind/kiso/input-otp.css +10 -0
- data/app/assets/tailwind/kiso/radio-group.css +17 -0
- data/app/helpers/kiso/component_helper.rb +46 -27
- data/app/helpers/kiso/icon_helper.rb +53 -9
- data/app/helpers/kiso/theme_helper.rb +38 -0
- data/app/javascript/controllers/kiso/combobox_controller.js +616 -0
- data/app/javascript/controllers/kiso/command_controller.js +184 -0
- data/app/javascript/controllers/kiso/command_dialog_controller.js +104 -0
- data/app/javascript/controllers/kiso/dropdown_menu_controller.js +684 -0
- data/app/javascript/controllers/kiso/index.d.ts +12 -0
- data/app/javascript/controllers/kiso/index.js +42 -0
- data/app/javascript/controllers/kiso/input_otp_controller.js +195 -0
- data/app/javascript/controllers/kiso/popover_controller.js +254 -0
- data/app/javascript/controllers/kiso/select_controller.js +307 -0
- data/app/javascript/controllers/kiso/sidebar_controller.js +84 -0
- data/app/javascript/controllers/kiso/theme_controller.js +89 -0
- data/app/javascript/controllers/kiso/toggle_controller.js +24 -0
- data/app/javascript/controllers/kiso/toggle_group_controller.js +128 -0
- data/app/javascript/kiso/utils/focusable.js +8 -0
- data/app/javascript/kiso/utils/highlight.js +43 -0
- data/app/javascript/kiso/utils/positioning.js +86 -0
- data/app/javascript/kiso/vendor/floating-ui-core.js +1 -0
- data/app/javascript/kiso/vendor/floating-ui-dom.js +1 -0
- data/app/views/kiso/components/_alert.html.erb +1 -1
- data/app/views/kiso/components/_avatar.html.erb +23 -0
- data/app/views/kiso/components/_badge.html.erb +1 -1
- data/app/views/kiso/components/_breadcrumb.html.erb +8 -0
- data/app/views/kiso/components/_button.html.erb +1 -1
- data/app/views/kiso/components/_card.html.erb +1 -1
- data/app/views/kiso/components/_checkbox.html.erb +7 -0
- data/app/views/kiso/components/_color_mode_button.html.erb +14 -0
- data/app/views/kiso/components/_color_mode_select.html.erb +24 -0
- data/app/views/kiso/components/_combobox.html.erb +12 -0
- data/app/views/kiso/components/_command.html.erb +7 -0
- data/app/views/kiso/components/_dashboard_group.html.erb +14 -0
- data/app/views/kiso/components/_dashboard_navbar.html.erb +7 -0
- data/app/views/kiso/components/_dashboard_panel.html.erb +7 -0
- data/app/views/kiso/components/_dashboard_sidebar.html.erb +11 -0
- data/app/views/kiso/components/_dashboard_toolbar.html.erb +7 -0
- data/app/views/kiso/components/_dropdown_menu.html.erb +7 -0
- data/app/views/kiso/components/{_empty_state.html.erb → _empty.html.erb} +2 -2
- data/app/views/kiso/components/_field.html.erb +12 -0
- data/app/views/kiso/components/_field_group.html.erb +7 -0
- data/app/views/kiso/components/_field_set.html.erb +7 -0
- data/app/views/kiso/components/_input.html.erb +8 -0
- data/app/views/kiso/components/_input_group.html.erb +8 -0
- data/app/views/kiso/components/_input_otp.html.erb +22 -0
- data/app/views/kiso/components/_kbd.html.erb +7 -0
- data/app/views/kiso/components/_label.html.erb +5 -0
- data/app/views/kiso/components/_nav.html.erb +7 -0
- data/app/views/kiso/components/_pagination.html.erb +9 -0
- data/app/views/kiso/components/_popover.html.erb +8 -0
- data/app/views/kiso/components/_radio_group.html.erb +8 -0
- data/app/views/kiso/components/_select.html.erb +8 -0
- data/app/views/kiso/components/_select_native.html.erb +16 -0
- data/app/views/kiso/components/_separator.html.erb +1 -1
- data/app/views/kiso/components/_stats_card.html.erb +1 -1
- data/app/views/kiso/components/_stats_grid.html.erb +1 -1
- data/app/views/kiso/components/_switch.html.erb +10 -0
- data/app/views/kiso/components/_table.html.erb +2 -1
- data/app/views/kiso/components/_textarea.html.erb +9 -0
- data/app/views/kiso/components/_toggle.html.erb +12 -0
- data/app/views/kiso/components/_toggle_group.html.erb +12 -0
- data/app/views/kiso/components/alert/_description.html.erb +1 -1
- data/app/views/kiso/components/alert/_title.html.erb +1 -1
- data/app/views/kiso/components/avatar/_badge.html.erb +7 -0
- data/app/views/kiso/components/avatar/_fallback.html.erb +7 -0
- data/app/views/kiso/components/avatar/_group.html.erb +7 -0
- data/app/views/kiso/components/avatar/_group_count.html.erb +7 -0
- data/app/views/kiso/components/avatar/_image.html.erb +6 -0
- data/app/views/kiso/components/breadcrumb/_ellipsis.html.erb +10 -0
- data/app/views/kiso/components/breadcrumb/_item.html.erb +7 -0
- data/app/views/kiso/components/breadcrumb/_link.html.erb +7 -0
- data/app/views/kiso/components/breadcrumb/_list.html.erb +7 -0
- data/app/views/kiso/components/breadcrumb/_page.html.erb +9 -0
- data/app/views/kiso/components/breadcrumb/_separator.html.erb +9 -0
- data/app/views/kiso/components/card/_action.html.erb +7 -0
- data/app/views/kiso/components/card/_content.html.erb +1 -1
- data/app/views/kiso/components/card/_description.html.erb +1 -1
- data/app/views/kiso/components/card/_footer.html.erb +1 -1
- data/app/views/kiso/components/card/_header.html.erb +1 -1
- data/app/views/kiso/components/card/_title.html.erb +1 -1
- data/app/views/kiso/components/combobox/_chip.html.erb +19 -0
- data/app/views/kiso/components/combobox/_chips.html.erb +20 -0
- data/app/views/kiso/components/combobox/_chips_input.html.erb +10 -0
- data/app/views/kiso/components/combobox/_content.html.erb +9 -0
- data/app/views/kiso/components/combobox/_empty.html.erb +9 -0
- data/app/views/kiso/components/combobox/_group.html.erb +8 -0
- data/app/views/kiso/components/combobox/_input.html.erb +23 -0
- data/app/views/kiso/components/combobox/_item.html.erb +19 -0
- data/app/views/kiso/components/combobox/_label.html.erb +7 -0
- data/app/views/kiso/components/combobox/_list.html.erb +10 -0
- data/app/views/kiso/components/combobox/_separator.html.erb +6 -0
- data/app/views/kiso/components/command/_dialog.html.erb +11 -0
- data/app/views/kiso/components/command/_empty.html.erb +9 -0
- data/app/views/kiso/components/command/_group.html.erb +14 -0
- data/app/views/kiso/components/command/_input.html.erb +16 -0
- data/app/views/kiso/components/command/_item.html.erb +13 -0
- data/app/views/kiso/components/command/_list.html.erb +10 -0
- data/app/views/kiso/components/command/_separator.html.erb +7 -0
- data/app/views/kiso/components/command/_shortcut.html.erb +7 -0
- data/app/views/kiso/components/dashboard_navbar/_toggle.html.erb +11 -0
- data/app/views/kiso/components/dashboard_sidebar/_collapse.html.erb +12 -0
- data/app/views/kiso/components/dashboard_sidebar/_footer.html.erb +7 -0
- data/app/views/kiso/components/dashboard_sidebar/_header.html.erb +7 -0
- data/app/views/kiso/components/dashboard_sidebar/_toggle.html.erb +11 -0
- data/app/views/kiso/components/dashboard_toolbar/_left.html.erb +7 -0
- data/app/views/kiso/components/dashboard_toolbar/_right.html.erb +7 -0
- data/app/views/kiso/components/dropdown_menu/_checkbox_item.html.erb +18 -0
- data/app/views/kiso/components/dropdown_menu/_content.html.erb +10 -0
- data/app/views/kiso/components/dropdown_menu/_group.html.erb +8 -0
- data/app/views/kiso/components/dropdown_menu/_item.html.erb +15 -0
- data/app/views/kiso/components/dropdown_menu/_label.html.erb +8 -0
- data/app/views/kiso/components/dropdown_menu/_radio_group.html.erb +10 -0
- data/app/views/kiso/components/dropdown_menu/_radio_item.html.erb +19 -0
- data/app/views/kiso/components/dropdown_menu/_separator.html.erb +6 -0
- data/app/views/kiso/components/dropdown_menu/_shortcut.html.erb +7 -0
- data/app/views/kiso/components/dropdown_menu/_sub.html.erb +8 -0
- data/app/views/kiso/components/dropdown_menu/_sub_content.html.erb +10 -0
- data/app/views/kiso/components/dropdown_menu/_sub_trigger.html.erb +12 -0
- data/app/views/kiso/components/dropdown_menu/_trigger.html.erb +9 -0
- data/app/views/kiso/components/empty/_content.html.erb +7 -0
- data/app/views/kiso/components/empty/_description.html.erb +7 -0
- data/app/views/kiso/components/empty/_header.html.erb +7 -0
- data/app/views/kiso/components/empty/_media.html.erb +7 -0
- data/app/views/kiso/components/empty/_title.html.erb +7 -0
- data/app/views/kiso/components/field/_content.html.erb +7 -0
- data/app/views/kiso/components/field/_description.html.erb +7 -0
- data/app/views/kiso/components/field/_error.html.erb +22 -0
- data/app/views/kiso/components/field/_label.html.erb +5 -0
- data/app/views/kiso/components/field/_separator.html.erb +15 -0
- data/app/views/kiso/components/field/_title.html.erb +7 -0
- data/app/views/kiso/components/field_set/_legend.html.erb +9 -0
- data/app/views/kiso/components/input_group/_addon.html.erb +7 -0
- data/app/views/kiso/components/input_otp/_group.html.erb +7 -0
- data/app/views/kiso/components/input_otp/_separator.html.erb +8 -0
- data/app/views/kiso/components/input_otp/_slot.html.erb +11 -0
- data/app/views/kiso/components/kbd/_group.html.erb +7 -0
- data/app/views/kiso/components/nav/_item.html.erb +15 -0
- data/app/views/kiso/components/nav/_section.html.erb +37 -0
- data/app/views/kiso/components/nav/_section_title.html.erb +7 -0
- data/app/views/kiso/components/pagination/_content.html.erb +7 -0
- data/app/views/kiso/components/pagination/_ellipsis.html.erb +9 -0
- data/app/views/kiso/components/pagination/_item.html.erb +7 -0
- data/app/views/kiso/components/pagination/_link.html.erb +9 -0
- data/app/views/kiso/components/pagination/_next.html.erb +12 -0
- data/app/views/kiso/components/pagination/_previous.html.erb +12 -0
- data/app/views/kiso/components/popover/_anchor.html.erb +8 -0
- data/app/views/kiso/components/popover/_content.html.erb +11 -0
- data/app/views/kiso/components/popover/_description.html.erb +7 -0
- data/app/views/kiso/components/popover/_header.html.erb +7 -0
- data/app/views/kiso/components/popover/_title.html.erb +7 -0
- data/app/views/kiso/components/popover/_trigger.html.erb +9 -0
- data/app/views/kiso/components/radio_group/_item.html.erb +6 -0
- data/app/views/kiso/components/select/_content.html.erb +10 -0
- data/app/views/kiso/components/select/_group.html.erb +8 -0
- data/app/views/kiso/components/select/_item.html.erb +19 -0
- data/app/views/kiso/components/select/_label.html.erb +7 -0
- data/app/views/kiso/components/select/_separator.html.erb +6 -0
- data/app/views/kiso/components/select/_trigger.html.erb +13 -0
- data/app/views/kiso/components/select/_value.html.erb +11 -0
- data/app/views/kiso/components/stats_card/_description.html.erb +1 -1
- data/app/views/kiso/components/stats_card/_header.html.erb +1 -1
- data/app/views/kiso/components/stats_card/_label.html.erb +1 -1
- data/app/views/kiso/components/stats_card/_value.html.erb +1 -1
- data/app/views/kiso/components/table/_body.html.erb +1 -1
- data/app/views/kiso/components/table/_caption.html.erb +1 -1
- data/app/views/kiso/components/table/_cell.html.erb +1 -1
- data/app/views/kiso/components/table/_footer.html.erb +1 -1
- data/app/views/kiso/components/table/_head.html.erb +1 -1
- data/app/views/kiso/components/table/_header.html.erb +1 -1
- data/app/views/kiso/components/table/_row.html.erb +1 -1
- data/app/views/kiso/components/toggle_group/_item.html.erb +13 -0
- data/config/deploy.docs.yml +31 -0
- data/config/deploy.yml +34 -0
- data/config/importmap.rb +10 -0
- data/lib/kiso/cli/base.rb +15 -0
- data/lib/kiso/cli/icons.rb +2 -1
- data/lib/kiso/cli/main.rb +6 -0
- data/lib/kiso/cli/make.rb +22 -12
- data/lib/kiso/configuration.rb +54 -0
- data/lib/kiso/engine.rb +36 -1
- data/lib/kiso/theme_overrides.rb +130 -0
- data/lib/kiso/themes/alert.rb +16 -1
- data/lib/kiso/themes/avatar.rb +53 -0
- data/lib/kiso/themes/badge.rb +15 -5
- data/lib/kiso/themes/breadcrumb.rb +44 -0
- data/lib/kiso/themes/button.rb +15 -2
- data/lib/kiso/themes/card.rb +18 -2
- data/lib/kiso/themes/checkbox.rb +33 -0
- data/lib/kiso/themes/color_mode_button.rb +15 -0
- data/lib/kiso/themes/color_mode_select.rb +7 -0
- data/lib/kiso/themes/combobox.rb +97 -0
- data/lib/kiso/themes/command.rb +79 -0
- data/lib/kiso/themes/dashboard.rb +51 -0
- data/lib/kiso/themes/dropdown_menu.rb +108 -0
- data/lib/kiso/themes/empty.rb +54 -0
- data/lib/kiso/themes/field.rb +76 -0
- data/lib/kiso/themes/field_group.rb +15 -0
- data/lib/kiso/themes/field_set.rb +32 -0
- data/lib/kiso/themes/input.rb +33 -0
- data/lib/kiso/themes/input_group.rb +39 -0
- data/lib/kiso/themes/input_otp.rb +46 -0
- data/lib/kiso/themes/kbd.rb +31 -0
- data/lib/kiso/themes/label.rb +16 -0
- data/lib/kiso/themes/nav.rb +27 -0
- data/lib/kiso/themes/pagination.rb +73 -0
- data/lib/kiso/themes/popover.rb +32 -0
- data/lib/kiso/themes/radio_group.rb +43 -0
- data/lib/kiso/themes/select.rb +78 -0
- data/lib/kiso/themes/select_native.rb +49 -0
- data/lib/kiso/themes/separator.rb +8 -2
- data/lib/kiso/themes/shared.rb +51 -0
- data/lib/kiso/themes/stats_card.rb +26 -14
- data/lib/kiso/themes/switch.rb +56 -0
- data/lib/kiso/themes/table.rb +18 -15
- data/lib/kiso/themes/textarea.rb +33 -0
- data/lib/kiso/themes/toggle.rb +71 -0
- data/lib/kiso/themes/toggle_group.rb +13 -0
- data/lib/kiso/version.rb +4 -1
- data/lib/kiso.rb +70 -2
- metadata +183 -22
- data/app/views/kiso/components/empty_state/_content.html.erb +0 -7
- data/app/views/kiso/components/empty_state/_description.html.erb +0 -7
- data/app/views/kiso/components/empty_state/_header.html.erb +0 -7
- data/app/views/kiso/components/empty_state/_media.html.erb +0 -7
- data/app/views/kiso/components/empty_state/_title.html.erb +0 -7
- data/lib/kiso/themes/empty_state.rb +0 -42
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# Fieldset grouping for related form controls (e.g. checkbox/radio groups).
|
|
4
|
+
#
|
|
5
|
+
# Automatically tightens gap when containing checkbox or radio groups.
|
|
6
|
+
#
|
|
7
|
+
# @example
|
|
8
|
+
# FieldSet.render
|
|
9
|
+
#
|
|
10
|
+
# Sub-parts: {FieldLegend}
|
|
11
|
+
FieldSet = ClassVariants.build(
|
|
12
|
+
base: "flex flex-col gap-6 " \
|
|
13
|
+
"has-[>[data-slot=checkbox-group]]:gap-3 " \
|
|
14
|
+
"has-[>[data-slot=radio-group]]:gap-3"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# Heading for a {FieldSet}.
|
|
18
|
+
#
|
|
19
|
+
# Variants:
|
|
20
|
+
# - +variant+ — :legend (default, larger text), :label (smaller, label-sized)
|
|
21
|
+
FieldLegend = ClassVariants.build(
|
|
22
|
+
base: "mb-3 font-medium",
|
|
23
|
+
variants: {
|
|
24
|
+
variant: {
|
|
25
|
+
legend: "text-base",
|
|
26
|
+
label: "text-sm"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
defaults: {variant: :legend}
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# Single-line text input field.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# Input.render(variant: :outline, size: :md)
|
|
7
|
+
#
|
|
8
|
+
# Variants:
|
|
9
|
+
# - +variant+ — :outline (default), :soft, :ghost
|
|
10
|
+
# - +size+ — :sm, :md (default), :lg
|
|
11
|
+
Input = ClassVariants.build(
|
|
12
|
+
base: "text-foreground w-full min-w-0 rounded-md outline-none transition-[color,box-shadow] " \
|
|
13
|
+
"placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground " \
|
|
14
|
+
"file:text-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium " \
|
|
15
|
+
"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 " \
|
|
16
|
+
"focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary " \
|
|
17
|
+
"aria-invalid:ring-error aria-invalid:focus-visible:ring-error",
|
|
18
|
+
variants: {
|
|
19
|
+
variant: {
|
|
20
|
+
outline: "bg-background ring ring-inset ring-accented shadow-xs",
|
|
21
|
+
soft: "bg-elevated/50 hover:bg-elevated focus:bg-elevated",
|
|
22
|
+
ghost: "bg-transparent hover:bg-elevated focus:bg-elevated"
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
sm: "h-8 px-2.5 py-1 text-sm",
|
|
26
|
+
md: "h-9 px-3 py-1 text-base md:text-sm",
|
|
27
|
+
lg: "h-10 px-3 py-2 text-base"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
defaults: {variant: :outline, size: :md}
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# Wrapper that combines an input with leading/trailing addons (icons, text, buttons).
|
|
4
|
+
#
|
|
5
|
+
# Resets the inner input's ring/shadow so the group ring applies uniformly.
|
|
6
|
+
#
|
|
7
|
+
# @example
|
|
8
|
+
# InputGroup.render
|
|
9
|
+
#
|
|
10
|
+
# Sub-parts: {InputGroupAddon}
|
|
11
|
+
InputGroup = ClassVariants.build(
|
|
12
|
+
base: "relative flex w-full items-center rounded-md text-foreground " \
|
|
13
|
+
"ring ring-inset ring-accented shadow-xs " \
|
|
14
|
+
"h-9 min-w-0 has-[>textarea]:h-auto " \
|
|
15
|
+
"has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-inset has-[:focus-visible]:ring-primary " \
|
|
16
|
+
"has-[[aria-invalid]]:ring-error " \
|
|
17
|
+
"[&_input]:flex-1 [&_input]:rounded-none [&_input]:border-0 [&_input]:shadow-none [&_input]:ring-0 [&_input]:bg-transparent [&_input]:focus-visible:ring-0 " \
|
|
18
|
+
"[&_textarea]:flex-1 [&_textarea]:rounded-none [&_textarea]:border-0 [&_textarea]:shadow-none [&_textarea]:ring-0 [&_textarea]:bg-transparent [&_textarea]:focus-visible:ring-0",
|
|
19
|
+
variants: {},
|
|
20
|
+
defaults: {}
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
# Leading or trailing addon element (icon, text, button) inside an {InputGroup}.
|
|
24
|
+
#
|
|
25
|
+
# Variants:
|
|
26
|
+
# - +align+ — :start (default, left side), :end (right side)
|
|
27
|
+
InputGroupAddon = ClassVariants.build(
|
|
28
|
+
base: "text-muted-foreground flex items-center justify-center gap-2 py-1.5 text-sm font-medium select-none " \
|
|
29
|
+
"[&_svg:not([class*='size-'])]:size-4",
|
|
30
|
+
variants: {
|
|
31
|
+
align: {
|
|
32
|
+
start: "ps-3",
|
|
33
|
+
end: "pe-3"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
defaults: {align: :start}
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# OTP/PIN code input container. Positions a transparent real +<input>+
|
|
4
|
+
# over visual slot divs managed by the +kiso--input-otp+ Stimulus controller.
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# InputOtp.render
|
|
8
|
+
InputOtp = ClassVariants.build(
|
|
9
|
+
base: "relative text-foreground flex items-center gap-2 has-disabled:opacity-50"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
# Groups adjacent slots visually (e.g., first 3 digits, last 3 digits).
|
|
13
|
+
InputOtpGroup = ClassVariants.build(
|
|
14
|
+
base: "flex items-center"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# Individual character display slot with connected borders.
|
|
18
|
+
# Content and active state managed by +kiso--input-otp+ controller.
|
|
19
|
+
#
|
|
20
|
+
# @example
|
|
21
|
+
# InputOtpSlot.render(size: :md)
|
|
22
|
+
InputOtpSlot = ClassVariants.build(
|
|
23
|
+
base: "border-accented relative flex items-center justify-center " \
|
|
24
|
+
"border-y border-r shadow-xs transition-all outline-none " \
|
|
25
|
+
"first:rounded-l-md first:border-l last:rounded-r-md " \
|
|
26
|
+
"data-[active=true]:z-10 data-[active=true]:border-primary " \
|
|
27
|
+
"data-[active=true]:ring-[3px] data-[active=true]:ring-primary/50 " \
|
|
28
|
+
"aria-invalid:border-error " \
|
|
29
|
+
"data-[active=true]:aria-invalid:border-error " \
|
|
30
|
+
"data-[active=true]:aria-invalid:ring-error/20",
|
|
31
|
+
variants: {
|
|
32
|
+
size: {
|
|
33
|
+
sm: "size-8 text-xs",
|
|
34
|
+
md: "size-9 text-sm",
|
|
35
|
+
lg: "size-10 text-base"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
defaults: {size: :md}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Separator between groups (renders a minus icon by default).
|
|
42
|
+
InputOtpSeparator = ClassVariants.build(
|
|
43
|
+
base: "flex items-center text-muted-foreground [&>svg]:size-4"
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# Keyboard shortcut indicator (e.g. +Ctrl+K+, +Cmd+S+).
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# Kbd.render(size: :md)
|
|
7
|
+
#
|
|
8
|
+
# Variants:
|
|
9
|
+
# - +size+ — :sm, :md (default), :lg
|
|
10
|
+
#
|
|
11
|
+
# Sub-parts: {KbdGroup}
|
|
12
|
+
Kbd = ClassVariants.build(
|
|
13
|
+
base: "bg-muted text-foreground pointer-events-none inline-flex items-center " \
|
|
14
|
+
"justify-center gap-1 rounded-sm font-sans font-medium select-none " \
|
|
15
|
+
"[&_svg:not([class*='size-'])]:size-3",
|
|
16
|
+
variants: {
|
|
17
|
+
size: {
|
|
18
|
+
sm: "h-4 min-w-4 px-0.5 text-xs",
|
|
19
|
+
md: "h-5 min-w-5 px-1 text-xs",
|
|
20
|
+
lg: "h-6 min-w-6 px-1.5 text-xs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
defaults: {size: :md}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Inline container for multiple {Kbd} elements (e.g. +Ctrl+ + +K+).
|
|
27
|
+
KbdGroup = ClassVariants.build(
|
|
28
|
+
base: "inline-flex items-center gap-1"
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# Standalone text label for form controls.
|
|
4
|
+
#
|
|
5
|
+
# Automatically dims when the associated control is disabled (via
|
|
6
|
+
# +group-data-[disabled]+ and +peer-disabled+ selectors).
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# Label.render
|
|
10
|
+
Label = ClassVariants.build(
|
|
11
|
+
base: "flex items-center gap-2 text-sm leading-none font-medium select-none " \
|
|
12
|
+
"group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 " \
|
|
13
|
+
"peer-disabled:cursor-not-allowed peer-disabled:opacity-50"
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
Nav = ClassVariants.build(
|
|
4
|
+
base: "flex flex-col gap-2"
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
NavSection = ClassVariants.build(
|
|
8
|
+
base: "relative flex w-full min-w-0 flex-col gap-1 p-2"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
NavSectionTitle = ClassVariants.build(
|
|
12
|
+
base: "flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-muted-foreground cursor-pointer select-none list-none [&::-webkit-details-marker]:hidden"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
NavSectionContent = ClassVariants.build(
|
|
16
|
+
base: "flex w-full min-w-0 flex-col gap-1 text-sm"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
NavItem = ClassVariants.build(
|
|
20
|
+
base: "group relative w-full flex items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm outline-hidden transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 focus-visible:ring-ring data-[active=true]:bg-accent data-[active=true]:font-medium data-[active=true]:text-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
NavItemBadge = ClassVariants.build(
|
|
24
|
+
base: "ms-auto pointer-events-none flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none"
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# @return [String] shared base classes for all pagination link-type elements.
|
|
4
|
+
# Matches shadcn's buttonVariants base (ghost/outline neutral).
|
|
5
|
+
PAGINATION_LINK_BASE = "inline-flex items-center justify-center whitespace-nowrap rounded-md " \
|
|
6
|
+
"text-sm font-medium transition-all " \
|
|
7
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2 " \
|
|
8
|
+
"disabled:pointer-events-none disabled:opacity-50 " \
|
|
9
|
+
"aria-disabled:cursor-not-allowed aria-disabled:opacity-50 " \
|
|
10
|
+
"#{Shared::SVG_BASE}"
|
|
11
|
+
|
|
12
|
+
# @return [Hash] shared active/inactive variants for pagination links.
|
|
13
|
+
# +active: true+ renders outline neutral style, +active: false+ renders ghost.
|
|
14
|
+
PAGINATION_ACTIVE_VARIANTS = {
|
|
15
|
+
active: {
|
|
16
|
+
true => "ring ring-inset text-foreground bg-background ring-accented " \
|
|
17
|
+
"hover:bg-elevated focus-visible:ring-2 focus-visible:ring-inverted",
|
|
18
|
+
false => "text-foreground hover:bg-elevated active:bg-accented/75 focus-visible:outline-inverted"
|
|
19
|
+
}
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
# Page navigation with numbered links, prev/next buttons, and ellipsis.
|
|
23
|
+
#
|
|
24
|
+
# @example
|
|
25
|
+
# Pagination.render
|
|
26
|
+
#
|
|
27
|
+
# Sub-parts: {PaginationContent}, {PaginationItem}, {PaginationLink},
|
|
28
|
+
# {PaginationPrevious}, {PaginationNext}, {PaginationEllipsis}
|
|
29
|
+
Pagination = ClassVariants.build(
|
|
30
|
+
base: "mx-auto flex w-full justify-center"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Flex row container for pagination items.
|
|
34
|
+
PaginationContent = ClassVariants.build(
|
|
35
|
+
base: "flex flex-row items-center gap-1"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Wrapper for a single pagination element (link, ellipsis, etc.).
|
|
39
|
+
PaginationItem = ClassVariants.build(
|
|
40
|
+
base: ""
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Square button for a page number. Switches between ghost and outline
|
|
44
|
+
# style based on the +active+ variant.
|
|
45
|
+
#
|
|
46
|
+
# Variants:
|
|
47
|
+
# - +active+ — +true+ (outline, current page), +false+ (default, ghost)
|
|
48
|
+
PaginationLink = ClassVariants.build(
|
|
49
|
+
base: "#{PAGINATION_LINK_BASE} size-9",
|
|
50
|
+
variants: PAGINATION_ACTIVE_VARIANTS,
|
|
51
|
+
defaults: {active: false}
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# "Previous" navigation link with chevron icon.
|
|
55
|
+
PaginationPrevious = ClassVariants.build(
|
|
56
|
+
base: "#{PAGINATION_LINK_BASE} h-9 gap-1 px-2.5 sm:pl-2.5",
|
|
57
|
+
variants: PAGINATION_ACTIVE_VARIANTS,
|
|
58
|
+
defaults: {active: false}
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# "Next" navigation link with chevron icon.
|
|
62
|
+
PaginationNext = ClassVariants.build(
|
|
63
|
+
base: "#{PAGINATION_LINK_BASE} h-9 gap-1 px-2.5 sm:pr-2.5",
|
|
64
|
+
variants: PAGINATION_ACTIVE_VARIANTS,
|
|
65
|
+
defaults: {active: false}
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Ellipsis indicator for skipped page ranges.
|
|
69
|
+
PaginationEllipsis = ClassVariants.build(
|
|
70
|
+
base: "pointer-events-none flex size-9 items-center justify-center text-muted-foreground"
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# Floating panel anchored to a trigger element.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# PopoverContent.render
|
|
7
|
+
#
|
|
8
|
+
# Sub-parts: {PopoverContent}, {PopoverHeader}, {PopoverTitle},
|
|
9
|
+
# {PopoverDescription}
|
|
10
|
+
|
|
11
|
+
# The floating panel itself. Positioned via the Popover Stimulus controller.
|
|
12
|
+
PopoverContent = ClassVariants.build(
|
|
13
|
+
base: "bg-background text-foreground z-50 w-72 rounded-md " \
|
|
14
|
+
"ring ring-inset ring-border p-4 shadow-md outline-hidden"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# Header section with title and description.
|
|
18
|
+
PopoverHeader = ClassVariants.build(
|
|
19
|
+
base: "flex flex-col gap-1 text-sm"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# Popover heading text.
|
|
23
|
+
PopoverTitle = ClassVariants.build(
|
|
24
|
+
base: "font-medium"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Popover body text.
|
|
28
|
+
PopoverDescription = ClassVariants.build(
|
|
29
|
+
base: "text-muted-foreground"
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# Grid container for a set of {RadioGroupItem} elements.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# RadioGroup.render
|
|
7
|
+
#
|
|
8
|
+
# Sub-parts: {RadioGroupItem}
|
|
9
|
+
RadioGroup = ClassVariants.build(
|
|
10
|
+
base: "grid gap-3"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
# Native +<input type="radio">+ styled with +appearance-none+ and semantic
|
|
14
|
+
# color tokens. Uses the same color compound variant pattern as {Checkbox}.
|
|
15
|
+
#
|
|
16
|
+
# @example
|
|
17
|
+
# RadioGroupItem.render(color: :primary)
|
|
18
|
+
#
|
|
19
|
+
# Variants:
|
|
20
|
+
# - +color+ — :primary (default), :secondary, :success, :info, :warning, :error, :neutral
|
|
21
|
+
RadioGroupItem = ClassVariants.build(
|
|
22
|
+
base: "appearance-none aspect-square size-4 shrink-0 rounded-full " \
|
|
23
|
+
"ring ring-inset ring-accented shadow-xs " \
|
|
24
|
+
"transition-[color,box-shadow] outline-none " \
|
|
25
|
+
"disabled:cursor-not-allowed disabled:opacity-50 " \
|
|
26
|
+
"focus-visible:ring-[3px] " \
|
|
27
|
+
"aria-invalid:ring-error/30 aria-invalid:ring-2",
|
|
28
|
+
variants: {
|
|
29
|
+
color: COLORS.index_with { "" }
|
|
30
|
+
},
|
|
31
|
+
compound_variants: [
|
|
32
|
+
{color: :primary, class: "checked:bg-primary checked:ring-primary checked:text-primary-foreground focus-visible:ring-primary/50"},
|
|
33
|
+
{color: :secondary, class: "checked:bg-secondary checked:ring-secondary checked:text-secondary-foreground focus-visible:ring-secondary/50"},
|
|
34
|
+
{color: :success, class: "checked:bg-success checked:ring-success checked:text-success-foreground focus-visible:ring-success/50"},
|
|
35
|
+
{color: :info, class: "checked:bg-info checked:ring-info checked:text-info-foreground focus-visible:ring-info/50"},
|
|
36
|
+
{color: :warning, class: "checked:bg-warning checked:ring-warning checked:text-warning-foreground focus-visible:ring-warning/50"},
|
|
37
|
+
{color: :error, class: "checked:bg-error checked:ring-error checked:text-error-foreground focus-visible:ring-error/50"},
|
|
38
|
+
{color: :neutral, class: "checked:bg-inverted checked:ring-inverted checked:text-inverted-foreground focus-visible:ring-inverted/50"}
|
|
39
|
+
],
|
|
40
|
+
defaults: {color: :primary}
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# Native-like select dropdown with custom styling and keyboard navigation.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# Select.render
|
|
7
|
+
#
|
|
8
|
+
# Sub-parts: {SelectTrigger}, {SelectValue}, {SelectContent}, {SelectGroup},
|
|
9
|
+
# {SelectLabel}, {SelectItem}, {SelectItemIndicator}, {SelectSeparator}
|
|
10
|
+
Select = ClassVariants.build(
|
|
11
|
+
base: "relative text-foreground"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
# Button that displays the selected value and opens the dropdown.
|
|
15
|
+
#
|
|
16
|
+
# Variants:
|
|
17
|
+
# - +size+ — :sm, :md (default)
|
|
18
|
+
SelectTrigger = ClassVariants.build(
|
|
19
|
+
base: "text-foreground flex w-full items-center justify-between gap-2 rounded-md " \
|
|
20
|
+
"bg-background px-3 py-2 text-sm whitespace-nowrap shadow-xs " \
|
|
21
|
+
"ring ring-inset ring-accented " \
|
|
22
|
+
"outline-none transition-[color,box-shadow] " \
|
|
23
|
+
"focus-visible:ring-2 focus-visible:ring-primary " \
|
|
24
|
+
"aria-invalid:ring-error aria-invalid:focus-visible:ring-error " \
|
|
25
|
+
"disabled:cursor-not-allowed disabled:opacity-50 " \
|
|
26
|
+
"#{Shared::SVG_BASE} " \
|
|
27
|
+
"[&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
28
|
+
variants: {
|
|
29
|
+
size: {
|
|
30
|
+
sm: "h-8",
|
|
31
|
+
md: "h-9"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
defaults: {size: :md}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Display area for the currently selected value inside {SelectTrigger}.
|
|
38
|
+
SelectValue = ClassVariants.build(
|
|
39
|
+
base: "line-clamp-1 flex items-center gap-2"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Dropdown panel containing the selectable items.
|
|
43
|
+
SelectContent = ClassVariants.build(
|
|
44
|
+
base: "relative bg-background text-foreground z-50 max-h-60 min-w-32 " \
|
|
45
|
+
"overflow-x-hidden overflow-y-auto rounded-md shadow-md ring ring-inset ring-border p-1"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Semantic grouping wrapper for related select items.
|
|
49
|
+
SelectGroup = ClassVariants.build(
|
|
50
|
+
base: ""
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Non-interactive heading for a {SelectGroup}.
|
|
54
|
+
SelectLabel = ClassVariants.build(
|
|
55
|
+
base: Shared::MENU_LABEL
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Selectable option within the dropdown.
|
|
59
|
+
SelectItem = ClassVariants.build(
|
|
60
|
+
base: "relative flex w-full cursor-default items-center gap-2 rounded-sm " \
|
|
61
|
+
"py-1.5 pr-8 pl-2 text-sm outline-none select-none " \
|
|
62
|
+
"data-[highlighted]:bg-elevated data-[highlighted]:text-foreground " \
|
|
63
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50 " \
|
|
64
|
+
"#{Shared::SVG_BASE} " \
|
|
65
|
+
"[&_svg:not([class*='text-'])]:text-muted-foreground"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Check mark indicator shown on the selected item.
|
|
69
|
+
SelectItemIndicator = ClassVariants.build(
|
|
70
|
+
base: "absolute right-2 flex size-3.5 items-center justify-center"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Horizontal divider between select items or groups.
|
|
74
|
+
SelectSeparator = ClassVariants.build(
|
|
75
|
+
base: "bg-border pointer-events-none -mx-1 my-1 h-px"
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# Wrapper for the select native element and its chevron icon overlay.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# SelectNativeWrapper.render
|
|
7
|
+
SelectNativeWrapper = ClassVariants.build(
|
|
8
|
+
base: "relative w-full has-[select:disabled]:opacity-50"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
# Native HTML `<select>` element with appearance-none and Kiso styling.
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# SelectNative.render(variant: :outline, size: :md)
|
|
15
|
+
#
|
|
16
|
+
# Variants:
|
|
17
|
+
# - +variant+ — :outline (default), :soft, :ghost
|
|
18
|
+
# - +size+ — :sm, :md (default), :lg
|
|
19
|
+
SelectNative = ClassVariants.build(
|
|
20
|
+
base: "text-foreground w-full min-w-0 appearance-none rounded-md pr-9 outline-none " \
|
|
21
|
+
"transition-[color,box-shadow] " \
|
|
22
|
+
"disabled:pointer-events-none disabled:cursor-not-allowed " \
|
|
23
|
+
"focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary " \
|
|
24
|
+
"aria-invalid:ring-error aria-invalid:focus-visible:ring-error",
|
|
25
|
+
variants: {
|
|
26
|
+
variant: {
|
|
27
|
+
outline: "bg-background ring ring-inset ring-accented shadow-xs",
|
|
28
|
+
soft: "bg-elevated/50 hover:bg-elevated focus:bg-elevated",
|
|
29
|
+
ghost: "bg-transparent hover:bg-elevated focus:bg-elevated"
|
|
30
|
+
},
|
|
31
|
+
size: {
|
|
32
|
+
sm: "h-8 px-2.5 py-1 text-sm",
|
|
33
|
+
md: "h-9 px-3 py-1 text-base md:text-sm",
|
|
34
|
+
lg: "h-10 px-3 py-2 text-base"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
defaults: {variant: :outline, size: :md}
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Chevron icon overlay positioned inside the select native wrapper.
|
|
41
|
+
#
|
|
42
|
+
# @example
|
|
43
|
+
# SelectNativeIcon.render
|
|
44
|
+
SelectNativeIcon = ClassVariants.build(
|
|
45
|
+
base: "text-muted-foreground pointer-events-none absolute top-1/2 right-3.5 " \
|
|
46
|
+
"size-4 -translate-y-1/2 opacity-50 select-none"
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
module Kiso
|
|
2
2
|
module Themes
|
|
3
|
+
# Visual divider between content sections.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# Separator.render(orientation: :horizontal)
|
|
7
|
+
#
|
|
8
|
+
# Variants:
|
|
9
|
+
# - +orientation+ — :horizontal (default), :vertical
|
|
10
|
+
#
|
|
3
11
|
# shadcn base: bg-border shrink-0
|
|
4
|
-
# Horizontal: h-px w-full
|
|
5
|
-
# Vertical: h-full w-px
|
|
6
12
|
Separator = ClassVariants.build(
|
|
7
13
|
base: "bg-border shrink-0",
|
|
8
14
|
variants: {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
# Theme definitions for all Kiso components.
|
|
3
|
+
#
|
|
4
|
+
# Each constant is a +ClassVariants+ instance that maps variant options
|
|
5
|
+
# to Tailwind CSS class strings. Call +.render+ with variant options to
|
|
6
|
+
# get the resolved class string:
|
|
7
|
+
#
|
|
8
|
+
# Kiso::Themes::Badge.render(color: :success, variant: :soft, size: :md)
|
|
9
|
+
# # => "inline-flex items-center ... bg-success/10 text-success ..."
|
|
10
|
+
#
|
|
11
|
+
# Compound components (Card, Table, Field, etc.) have multiple constants
|
|
12
|
+
# for the root and each sub-part (e.g. +Card+, +CardHeader+, +CardTitle+).
|
|
13
|
+
#
|
|
14
|
+
# @see project/design-system.md for compound variant formulas and token mapping
|
|
15
|
+
# @see project/component-strategy.md for architecture patterns
|
|
16
|
+
module Themes
|
|
17
|
+
# Shared class strings for patterns that are identical across multiple
|
|
18
|
+
# components. Using shared constants prevents drift when updating styles.
|
|
19
|
+
#
|
|
20
|
+
# Only extract constants that are byte-for-byte identical across components.
|
|
21
|
+
# Component-specific variations (e.g., CommandSeparator missing +my-1+,
|
|
22
|
+
# SelectSeparator with +pointer-events-none+) should remain inline to
|
|
23
|
+
# preserve shadcn fidelity.
|
|
24
|
+
module Shared
|
|
25
|
+
# Used by: Button, Toggle, ToggleGroupItem, SelectTrigger, SelectItem,
|
|
26
|
+
# ComboboxItem, CommandItem, DropdownMenuItem, DropdownMenuSubTrigger,
|
|
27
|
+
# DropdownMenuCheckboxItem, DropdownMenuRadioItem (via CHECKABLE_ITEM),
|
|
28
|
+
# PaginationLink/Previous/Next (via PAGINATION_LINK_BASE)
|
|
29
|
+
SVG_BASE = "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
30
|
+
|
|
31
|
+
# Used by: ComboboxSeparator, DropdownMenuSeparator
|
|
32
|
+
# (CommandSeparator omits my-1, SelectSeparator adds pointer-events-none — both per shadcn)
|
|
33
|
+
ITEM_SEPARATOR = "bg-border -mx-1 my-1 h-px"
|
|
34
|
+
|
|
35
|
+
# Used by: ComboboxLabel, SelectLabel
|
|
36
|
+
# (CommandGroupHeading adds font-medium — per shadcn)
|
|
37
|
+
MENU_LABEL = "text-muted-foreground px-2 py-1.5 text-xs"
|
|
38
|
+
|
|
39
|
+
# Used by: CommandShortcut, DropdownMenuShortcut
|
|
40
|
+
MENU_SHORTCUT = "text-muted-foreground ml-auto text-xs tracking-widest"
|
|
41
|
+
|
|
42
|
+
# Shared base for checkbox and radio items in DropdownMenu.
|
|
43
|
+
# These are structurally identical — same layout, same interactive states.
|
|
44
|
+
CHECKABLE_ITEM = "relative flex cursor-default items-center gap-2 rounded-sm " \
|
|
45
|
+
"py-1.5 pr-2 pl-8 text-sm outline-none select-none " \
|
|
46
|
+
"data-[highlighted]:bg-elevated data-[highlighted]:text-foreground " \
|
|
47
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50 " \
|
|
48
|
+
"#{SVG_BASE}"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
module Kiso
|
|
2
2
|
module Themes
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
3
|
+
# Compact card for displaying a single dashboard metric.
|
|
4
|
+
#
|
|
5
|
+
# Same variant axis as {Card} (outline/soft/subtle) with tighter spacing.
|
|
6
|
+
#
|
|
7
|
+
# @example
|
|
8
|
+
# StatsCard.render(variant: :outline)
|
|
9
|
+
#
|
|
10
|
+
# Variants:
|
|
11
|
+
# - +variant+ — :outline (default), :soft, :subtle
|
|
12
|
+
#
|
|
13
|
+
# Sub-parts: {StatsCardHeader}, {StatsCardLabel}, {StatsCardValue},
|
|
14
|
+
# {StatsCardDescription}
|
|
15
|
+
#
|
|
16
|
+
# Related: {StatsGrid} for responsive grid layout of multiple stats cards.
|
|
7
17
|
StatsCard = ClassVariants.build(
|
|
8
18
|
base: "flex flex-col gap-2 rounded-xl p-4 text-foreground",
|
|
9
19
|
variants: {
|
|
@@ -16,32 +26,34 @@ module Kiso
|
|
|
16
26
|
defaults: {variant: :outline}
|
|
17
27
|
)
|
|
18
28
|
|
|
19
|
-
#
|
|
20
|
-
# Flex row for label on left, optional icon/badge on right.
|
|
29
|
+
# Header row with label on the left and optional icon/badge on the right.
|
|
21
30
|
StatsCardHeader = ClassVariants.build(
|
|
22
31
|
base: "flex items-center justify-between gap-2"
|
|
23
32
|
)
|
|
24
33
|
|
|
25
|
-
#
|
|
26
|
-
# The metric name ("Total Revenue", "New Customers").
|
|
34
|
+
# The metric name (e.g. "Total Revenue", "New Customers").
|
|
27
35
|
StatsCardLabel = ClassVariants.build(
|
|
28
36
|
base: "text-sm font-medium text-muted-foreground"
|
|
29
37
|
)
|
|
30
38
|
|
|
31
|
-
#
|
|
32
|
-
#
|
|
39
|
+
# The prominent metric number (e.g. "$1,250.00", "45,678").
|
|
40
|
+
# Uses +tabular-nums+ for aligned digits.
|
|
33
41
|
StatsCardValue = ClassVariants.build(
|
|
34
42
|
base: "text-2xl font-semibold tabular-nums"
|
|
35
43
|
)
|
|
36
44
|
|
|
37
|
-
#
|
|
38
|
-
# Trend text, subtitle, or additional context.
|
|
45
|
+
# Supplementary text below the value (e.g. trend info, subtitle).
|
|
39
46
|
StatsCardDescription = ClassVariants.build(
|
|
40
47
|
base: "text-xs text-muted-foreground"
|
|
41
48
|
)
|
|
42
49
|
|
|
43
|
-
# Responsive grid
|
|
44
|
-
#
|
|
50
|
+
# Responsive grid layout for arranging multiple {StatsCard} instances.
|
|
51
|
+
#
|
|
52
|
+
# @example
|
|
53
|
+
# StatsGrid.render(columns: 4)
|
|
54
|
+
#
|
|
55
|
+
# Variants:
|
|
56
|
+
# - +columns+ — 2, 3, 4 (default)
|
|
45
57
|
StatsGrid = ClassVariants.build(
|
|
46
58
|
base: "grid grid-cols-1 gap-4",
|
|
47
59
|
variants: {
|