kiso 0.5.2.pre → 0.6.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/app/assets/tailwind/kiso/button.css +12 -3
- data/app/assets/tailwind/kiso/checkbox.css +13 -2
- data/app/assets/tailwind/kiso/color-mode.css +15 -3
- data/app/assets/tailwind/kiso/dashboard.css +97 -44
- data/app/assets/tailwind/kiso/dialog.css +39 -5
- data/app/assets/tailwind/kiso/engine.css +117 -34
- data/app/assets/tailwind/kiso/input-otp.css +24 -4
- data/app/assets/tailwind/kiso/palettes/blue.css +14 -5
- data/app/assets/tailwind/kiso/palettes/green.css +9 -5
- data/app/assets/tailwind/kiso/palettes/orange.css +9 -5
- data/app/assets/tailwind/kiso/palettes/violet.css +9 -5
- data/app/assets/tailwind/kiso/palettes/zinc.css +11 -7
- data/app/assets/tailwind/kiso/radio-group.css +11 -4
- data/app/assets/tailwind/kiso/slider.css +25 -6
- data/app/assets/tailwind/kiso/tooltip.css +37 -11
- data/app/helpers/kiso/app_component_helper.rb +83 -34
- data/app/helpers/kiso/component_helper.rb +227 -70
- data/app/helpers/kiso/icon_helper.rb +101 -39
- data/app/helpers/kiso/theme_helper.rb +50 -9
- data/app/helpers/kiso/ui_context_helper.rb +87 -35
- data/app/javascript/controllers/kiso/combobox_controller.js +10 -2
- data/app/javascript/controllers/kiso/command_controller.js +2 -0
- data/app/javascript/controllers/kiso/command_dialog_controller.js +4 -0
- data/app/javascript/controllers/kiso/dialog_controller.js +6 -1
- data/app/javascript/controllers/kiso/dialog_trigger_controller.js +1 -1
- data/app/javascript/controllers/kiso/dropdown_menu_controller.js +23 -5
- data/app/javascript/controllers/kiso/index.js +25 -0
- data/app/javascript/controllers/kiso/input_otp_controller.js +5 -3
- data/app/javascript/controllers/kiso/popover_controller.js +18 -4
- data/app/javascript/controllers/kiso/select_controller.js +10 -2
- data/app/javascript/controllers/kiso/sidebar_controller.js +26 -4
- data/app/javascript/controllers/kiso/slider_controller.js +3 -3
- data/app/javascript/controllers/kiso/theme_controller.js +2 -1
- data/app/javascript/controllers/kiso/toggle_controller.js +2 -0
- data/app/javascript/controllers/kiso/toggle_group_controller.js +3 -0
- data/app/javascript/controllers/kiso/tooltip_controller.js +3 -0
- data/app/javascript/kiso/utils/focusable.js +14 -0
- data/app/javascript/kiso/utils/highlight.js +15 -1
- data/app/views/kiso/components/_alert.html.erb +2 -0
- data/app/views/kiso/components/_alert_dialog.html.erb +5 -2
- data/app/views/kiso/components/_app.html.erb +2 -0
- data/app/views/kiso/components/_aspect_ratio.html.erb +1 -0
- data/app/views/kiso/components/_avatar.html.erb +6 -2
- data/app/views/kiso/components/_button.html.erb +3 -0
- data/app/views/kiso/components/_checkbox.html.erb +1 -0
- data/app/views/kiso/components/_color_mode_button.html.erb +2 -0
- data/app/views/kiso/components/_color_mode_select.html.erb +2 -0
- data/app/views/kiso/components/_combobox.html.erb +3 -0
- data/app/views/kiso/components/_command.html.erb +2 -0
- data/app/views/kiso/components/_dashboard_group.html.erb +4 -0
- data/app/views/kiso/components/_dashboard_navbar.html.erb +2 -0
- data/app/views/kiso/components/_dashboard_panel.html.erb +1 -0
- data/app/views/kiso/components/_dashboard_sidebar.html.erb +2 -0
- data/app/views/kiso/components/_dashboard_toolbar.html.erb +2 -0
- data/app/views/kiso/components/_dialog.html.erb +3 -0
- data/app/views/kiso/components/_dropdown_menu.html.erb +2 -0
- data/app/views/kiso/components/_empty.html.erb +2 -0
- data/app/views/kiso/components/_field.html.erb +2 -0
- data/app/views/kiso/components/_field_group.html.erb +1 -0
- data/app/views/kiso/components/_field_set.html.erb +1 -0
- data/app/views/kiso/components/_input_group.html.erb +1 -0
- data/app/views/kiso/components/_input_otp.html.erb +3 -0
- data/app/views/kiso/components/_nav.html.erb +2 -0
- data/app/views/kiso/components/_page_card.html.erb +3 -0
- data/app/views/kiso/components/_page_header.html.erb +3 -0
- data/app/views/kiso/components/_page_section.html.erb +2 -0
- data/app/views/kiso/components/_pagination.html.erb +2 -0
- data/app/views/kiso/components/_popover.html.erb +3 -0
- data/app/views/kiso/components/_select.html.erb +3 -0
- data/app/views/kiso/components/_select_native.html.erb +2 -0
- data/app/views/kiso/components/_separator.html.erb +2 -0
- data/app/views/kiso/components/_skeleton.html.erb +1 -0
- data/app/views/kiso/components/_slider.html.erb +4 -0
- data/app/views/kiso/components/_spinner.html.erb +2 -0
- data/app/views/kiso/components/_stats_card.html.erb +2 -0
- data/app/views/kiso/components/_stats_grid.html.erb +1 -0
- data/app/views/kiso/components/_switch.html.erb +2 -0
- data/app/views/kiso/components/_table.html.erb +2 -0
- data/app/views/kiso/components/_textarea.html.erb +3 -0
- data/app/views/kiso/components/_toggle.html.erb +2 -0
- data/app/views/kiso/components/_toggle_group.html.erb +2 -0
- data/app/views/kiso/components/_tooltip.html.erb +3 -0
- data/app/views/kiso/components/alert_dialog/_action.html.erb +1 -0
- data/app/views/kiso/components/alert_dialog/_cancel.html.erb +1 -0
- data/app/views/kiso/components/alert_dialog/_description.html.erb +1 -0
- data/app/views/kiso/components/alert_dialog/_title.html.erb +1 -0
- data/app/views/kiso/components/avatar/_image.html.erb +1 -0
- data/app/views/kiso/components/breadcrumb/_separator.html.erb +3 -0
- data/app/views/kiso/components/combobox/_chips.html.erb +3 -0
- data/app/views/kiso/components/command/_dialog.html.erb +2 -0
- data/app/views/kiso/components/dashboard_sidebar/_collapse.html.erb +2 -0
- data/app/views/kiso/components/dialog/_close.html.erb +1 -0
- data/app/views/kiso/components/field/_error.html.erb +4 -0
- data/app/views/kiso/components/field/_label.html.erb +2 -0
- data/app/views/kiso/components/field/_separator.html.erb +3 -0
- data/app/views/kiso/components/input_otp/_separator.html.erb +2 -0
- data/app/views/kiso/components/input_otp/_slot.html.erb +2 -0
- data/app/views/kiso/components/nav/_section.html.erb +4 -0
- data/app/views/kiso/components/tooltip/_content.html.erb +2 -0
- data/lib/generators/kiso/install/USAGE +23 -0
- data/lib/generators/kiso/install/install_generator.rb +91 -0
- data/lib/generators/kiso/install/templates/design_system.md.tt +190 -0
- data/lib/generators/kiso/install/templates/initializer.rb.tt +40 -0
- data/lib/kiso/cli/make.rb +6 -3
- data/lib/kiso/cli.rb +10 -0
- data/lib/kiso/color_utils.rb +31 -8
- data/lib/kiso/configuration.rb +11 -0
- data/lib/kiso/engine.rb +9 -2
- data/lib/kiso/propshaft_tailwind_stub_filter.rb +9 -2
- data/lib/kiso/themes/avatar.rb +40 -6
- data/lib/kiso/themes/badge.rb +5 -1
- data/lib/kiso/themes/color_mode_button.rb +11 -0
- data/lib/kiso/themes/color_mode_select.rb +7 -0
- data/lib/kiso/themes/dashboard.rb +28 -0
- data/lib/kiso/themes/dropdown_menu.rb +2 -2
- data/lib/kiso/themes/input_otp.rb +6 -3
- data/lib/kiso/themes/nav.rb +17 -0
- data/lib/kiso/themes/pagination.rb +9 -4
- data/lib/kiso/themes/shared.rb +27 -7
- data/lib/kiso/version.rb +5 -2
- metadata +5 -1
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
<%# locals: (variant: :outline, size: :md, disabled: false,
|
|
2
2
|
css_classes: "", **component_options) %>
|
|
3
|
+
<%# Multi-line text input. Yield a block to set default content (initial value). %>
|
|
3
4
|
<% component_options[:disabled] = true if disabled %>
|
|
4
5
|
<%= content_tag :textarea,
|
|
5
6
|
class: Kiso::Themes::Textarea.render(variant: variant, size: size, class: css_classes),
|
|
6
7
|
data: kiso_prepare_options(component_options, slot: "textarea"),
|
|
7
8
|
**component_options do %>
|
|
9
|
+
<%# capture { yield }.presence renders block content as the textarea's initial value,
|
|
10
|
+
or nil if no block was provided (avoids rendering empty whitespace). %>
|
|
8
11
|
<%= capture { yield }.presence %>
|
|
9
12
|
<% end %>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<%# locals: (variant: :default, size: :default, pressed: false, css_classes: "", **component_options) %>
|
|
2
|
+
<%# Two-state toggle button with aria-pressed. The Stimulus controller toggles
|
|
3
|
+
the data-state attribute between "on" and "off" on click. %>
|
|
2
4
|
<% component_options[:type] ||= :button
|
|
3
5
|
component_options[:"aria-pressed"] = pressed %>
|
|
4
6
|
<%= content_tag :button,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<%# locals: (type: :single, variant: :default, size: :default, css_classes: "", **component_options) %>
|
|
2
|
+
<%# Group of toggle buttons with single or multiple selection. The Stimulus controller
|
|
3
|
+
manages selection state and passes variant/size down to child toggle_group/items. %>
|
|
2
4
|
<%= content_tag :div,
|
|
3
5
|
class: Kiso::Themes::ToggleGroup.render(class: css_classes),
|
|
4
6
|
role: "group",
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
<%# locals: (text: nil, kbds: nil, side: :top, align: :center, delay: 0, ui: {}, css_classes: "", **component_options) %>
|
|
2
|
+
<%# Tooltip positioned via Floating UI using the popover API. Pass text: for a simple
|
|
3
|
+
tooltip with optional keyboard shortcut hints (kbds:). Without text:, compose
|
|
4
|
+
manually with tooltip/trigger and tooltip/content sub-parts. %>
|
|
2
5
|
<%= tag.div(
|
|
3
6
|
class: css_classes.presence,
|
|
4
7
|
data: kiso_prepare_options(component_options, slot: "tooltip",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<%# locals: (color: :primary, variant: :solid, size: :md, css_classes: "", **component_options) %>
|
|
2
|
+
<%# Confirm action button that closes the dialog. Uses Button theme for styling. %>
|
|
2
3
|
<%= tag.button type: "button",
|
|
3
4
|
class: Kiso::Themes::Button.render(color: color, variant: variant, size: size, class: css_classes),
|
|
4
5
|
data: kiso_prepare_options(component_options, slot: "alert-dialog-action",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<%# locals: (color: :primary, variant: :outline, size: :md, css_classes: "", **component_options) %>
|
|
2
|
+
<%# Cancel button that closes the dialog without confirming. Defaults to outline variant. %>
|
|
2
3
|
<%= tag.button type: "button",
|
|
3
4
|
class: Kiso::Themes::Button.render(color: color, variant: variant, size: size, class: css_classes),
|
|
4
5
|
data: kiso_prepare_options(component_options, slot: "alert-dialog-cancel",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<%# locals: (css_classes: "", **component_options) %>
|
|
2
|
+
<%# Auto-generates id from the parent dialog's @_kiso_alert_dialog_id for aria-describedby linking. %>
|
|
2
3
|
<% component_options[:id] = "#{@_kiso_alert_dialog_id}-description" if @_kiso_alert_dialog_id && !component_options.key?(:id) %>
|
|
3
4
|
<%= content_tag :p,
|
|
4
5
|
class: Kiso::Themes::AlertDialogDescription.render(class: css_classes),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<%# locals: (css_classes: "", **component_options) %>
|
|
2
|
+
<%# Auto-generates id from the parent dialog's @_kiso_alert_dialog_id for aria-labelledby linking. %>
|
|
2
3
|
<% component_options[:id] = "#{@_kiso_alert_dialog_id}-title" if @_kiso_alert_dialog_id && !component_options.key?(:id) %>
|
|
3
4
|
<%= content_tag :h2,
|
|
4
5
|
class: Kiso::Themes::AlertDialogTitle.render(class: css_classes),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<%# locals: (src:, alt: "", css_classes: "", **component_options) %>
|
|
2
|
+
<%# Avatar image that hides itself on load error, revealing the fallback text beneath. %>
|
|
2
3
|
<%= tag.img src: src, alt: alt,
|
|
3
4
|
class: Kiso::Themes::AvatarImage.render(class: css_classes),
|
|
4
5
|
data: kiso_prepare_options(component_options, slot: "avatar-image"),
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
<%# locals: (css_classes: "", **component_options) %>
|
|
2
|
+
<%# Breadcrumb separator between items. Defaults to a chevron-right icon;
|
|
3
|
+
yield a block to replace with a custom separator. %>
|
|
2
4
|
<%= content_tag :li,
|
|
3
5
|
class: Kiso::Themes::BreadcrumbSeparator.render(class: css_classes),
|
|
4
6
|
role: "presentation",
|
|
5
7
|
aria: { hidden: "true" },
|
|
6
8
|
data: kiso_prepare_options(component_options, slot: "breadcrumb-separator"),
|
|
7
9
|
**component_options do %>
|
|
10
|
+
<%# capture { yield }.presence returns nil when no block content, falling back to default icon. %>
|
|
8
11
|
<%= capture { yield }.presence || kiso_component_icon(:chevron_right, class: "size-3.5") %>
|
|
9
12
|
<% end %>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<%# locals: (css_classes: "", **component_options) %>
|
|
2
|
+
<%# Container for multi-select chips. Includes a <template> element that the
|
|
3
|
+
Stimulus controller clones to create new chips dynamically when items are selected. %>
|
|
2
4
|
<%= content_tag :div,
|
|
3
5
|
class: Kiso::Themes::ComboboxChips.render(class: css_classes),
|
|
4
6
|
data: kiso_prepare_options(component_options, slot: "combobox-chips",
|
|
5
7
|
kiso__combobox_target: "chips"),
|
|
6
8
|
**component_options do %>
|
|
7
9
|
<%= yield %>
|
|
10
|
+
<%# Chip template cloned by Stimulus for dynamically-added selections. %>
|
|
8
11
|
<%= tag.template data: { kiso__combobox_target: "chipTemplate" } do %>
|
|
9
12
|
<%= tag.span class: Kiso::Themes::ComboboxChip.render,
|
|
10
13
|
data: { slot: "combobox-chip", kiso__combobox_target: "chip" } do %>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<%# locals: (shortcut: "k", css_classes: "", **component_options) %>
|
|
2
|
+
<%# Command palette wrapped in a native <dialog>. Opens via Cmd/Ctrl+K (configurable
|
|
3
|
+
via shortcut: prop). Typically contains a command/input and command/list. %>
|
|
2
4
|
<%= content_tag :dialog,
|
|
3
5
|
class: Kiso::Themes::CommandDialog.render(class: css_classes),
|
|
4
6
|
data: kiso_prepare_options(component_options, slot: "command-dialog",
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<%# locals: (css_classes: "", **component_options) %>
|
|
2
|
+
<%# Sidebar collapse toggle for desktop. Shows open/closed panel icons that swap
|
|
3
|
+
visibility based on sidebar state via CSS. Placed inside the sidebar itself. %>
|
|
2
4
|
<%= content_tag :button,
|
|
3
5
|
class: Kiso::Themes::DashboardSidebarCollapse.render(class: css_classes),
|
|
4
6
|
data: kiso_prepare_options(component_options, slot: "dashboard-sidebar-collapse",
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<%# locals: (errors: [], css_classes: "", **component_options) %>
|
|
2
|
+
<%# Form field error display. Pass errors: as an array of strings (e.g., from
|
|
3
|
+
ActiveModel) or yield a block for fully custom error markup. Renders nothing
|
|
4
|
+
when both errors and block are empty. Multiple errors render as a bulleted list. %>
|
|
2
5
|
<% messages = Array(errors).compact.map(&:to_s).reject(&:blank?).uniq %>
|
|
6
|
+
<%# Block override: custom error content replaces the default message rendering. %>
|
|
3
7
|
<% content = capture { yield }.presence %>
|
|
4
8
|
<% if content || messages.any? %>
|
|
5
9
|
<%= content_tag :div,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<%# locals: (css_classes: "", **component_options) %>
|
|
2
|
+
<%# Wraps the base Label component with field-specific styling and a data-slot override.
|
|
3
|
+
Manually merges the data-slot because this delegates to kui(:label) which sets its own slot. %>
|
|
2
4
|
<% component_options[:data] = (component_options[:data] || {}).merge(slot: "field-label") %>
|
|
3
5
|
<%= kui(:label,
|
|
4
6
|
css_classes: Kiso::Themes::FieldLabel.render(class: css_classes),
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
<%# locals: (css_classes: "", **component_options) %>
|
|
2
|
+
<%# Horizontal divider between form fields. Optionally yield text (e.g., "or") to
|
|
3
|
+
display centered over the separator line. Sets data-content when text is present
|
|
4
|
+
so CSS can adjust spacing. %>
|
|
2
5
|
<% captured = capture { yield }.presence %>
|
|
3
6
|
<%= content_tag :div,
|
|
4
7
|
class: Kiso::Themes::FieldSeparator.render(class: css_classes),
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<%# locals: (css_classes: "", **component_options) %>
|
|
2
|
+
<%# Visual separator between OTP slot groups. Defaults to a minus icon;
|
|
3
|
+
yield a block to replace with a custom separator. %>
|
|
2
4
|
<%= content_tag :div,
|
|
3
5
|
role: "separator",
|
|
4
6
|
class: Kiso::Themes::InputOtpSeparator.render(class: css_classes),
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<%# locals: (size: :md, css_classes: "", **component_options) %>
|
|
2
|
+
<%# Individual character display slot for the OTP input. The Stimulus controller
|
|
3
|
+
populates the slot-char span and shows/hides the blinking caret. %>
|
|
2
4
|
<%= content_tag :div,
|
|
3
5
|
class: Kiso::Themes::InputOtpSlot.render(size: size, class: css_classes),
|
|
4
6
|
aria: { hidden: "true" },
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
<%# locals: (title: nil, open: true, collapsible: true, ui: {}, css_classes: "", **component_options) %>
|
|
2
|
+
<%# Navigation section with three rendering modes:
|
|
3
|
+
1. title + collapsible (default): native <details> element with toggle
|
|
4
|
+
2. title + collapsible: false: static section with non-interactive heading
|
|
5
|
+
3. No title: plain wrapper for ungrouped nav items %>
|
|
2
6
|
<% if title && collapsible %>
|
|
3
7
|
<%= content_tag :details,
|
|
4
8
|
class: Kiso::Themes::NavSection.render(class: css_classes),
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<%# locals: (css_classes: "", ui: {}, **component_options) %>
|
|
2
|
+
<%# Tooltip content panel using popover="manual" for visibility control.
|
|
3
|
+
Positioned by Floating UI via the parent tooltip's Stimulus controller. %>
|
|
2
4
|
<%= tag.div(
|
|
3
5
|
class: Kiso::Themes::TooltipContent.render(class: css_classes),
|
|
4
6
|
role: "tooltip",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Sets up Kiso in your application. Creates a well-commented initializer
|
|
3
|
+
with preset, theme, and icon configuration examples.
|
|
4
|
+
|
|
5
|
+
Optionally generates a DESIGN_SYSTEM.md with your app's spacing,
|
|
6
|
+
typography, color, and component conventions.
|
|
7
|
+
|
|
8
|
+
Examples:
|
|
9
|
+
bin/rails generate kiso:install
|
|
10
|
+
|
|
11
|
+
Creates:
|
|
12
|
+
config/initializers/kiso.rb
|
|
13
|
+
|
|
14
|
+
Optionally creates (interactive prompt):
|
|
15
|
+
DESIGN_SYSTEM.md
|
|
16
|
+
|
|
17
|
+
bin/rails generate kiso:install --no-skip-design-system --app-name="My App"
|
|
18
|
+
|
|
19
|
+
Creates both files without interactive prompts.
|
|
20
|
+
|
|
21
|
+
bin/rails generate kiso:install --skip-design-system
|
|
22
|
+
|
|
23
|
+
Creates only the initializer, skips the design system doc.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kiso
|
|
4
|
+
module Generators
|
|
5
|
+
# Sets up Kiso in a host application.
|
|
6
|
+
#
|
|
7
|
+
# Creates a well-commented initializer and optionally generates a
|
|
8
|
+
# design system document. No required arguments — interactive prompts
|
|
9
|
+
# handle optional inputs.
|
|
10
|
+
#
|
|
11
|
+
# @example Interactive (default)
|
|
12
|
+
# bin/rails generate kiso:install
|
|
13
|
+
#
|
|
14
|
+
# @example Non-interactive
|
|
15
|
+
# bin/rails generate kiso:install --no-skip-design-system --app-name="Outport"
|
|
16
|
+
class InstallGenerator < Rails::Generators::Base
|
|
17
|
+
source_root File.expand_path("templates", __dir__)
|
|
18
|
+
|
|
19
|
+
class_option :skip_design_system,
|
|
20
|
+
type: :boolean,
|
|
21
|
+
default: nil,
|
|
22
|
+
desc: "Skip generating DESIGN_SYSTEM.md (default: ask interactively)"
|
|
23
|
+
|
|
24
|
+
class_option :app_name,
|
|
25
|
+
type: :string,
|
|
26
|
+
default: nil,
|
|
27
|
+
desc: "App name for the design system doc header (default: ask interactively)"
|
|
28
|
+
|
|
29
|
+
def create_initializer
|
|
30
|
+
initializer_path = "config/initializers/kiso.rb"
|
|
31
|
+
if File.exist?(File.join(destination_root, initializer_path))
|
|
32
|
+
say_status :skip, initializer_path, :yellow
|
|
33
|
+
else
|
|
34
|
+
template "initializer.rb.tt", initializer_path
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def create_design_system
|
|
39
|
+
should_generate = case options[:skip_design_system]
|
|
40
|
+
when true then false
|
|
41
|
+
when false then true
|
|
42
|
+
else
|
|
43
|
+
yes?(<<~PROMPT)
|
|
44
|
+
|
|
45
|
+
Would you like to generate a Design System document?
|
|
46
|
+
This creates DESIGN_SYSTEM.md with your app's spacing, typography, color,
|
|
47
|
+
and component conventions — useful for team alignment and AI coding agents.
|
|
48
|
+
|
|
49
|
+
Generate DESIGN_SYSTEM.md? (y/n)
|
|
50
|
+
PROMPT
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
return unless should_generate
|
|
54
|
+
|
|
55
|
+
@app_name = resolve_app_name
|
|
56
|
+
template "design_system.md.tt", "DESIGN_SYSTEM.md"
|
|
57
|
+
@design_system_created = true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def print_next_steps
|
|
61
|
+
say ""
|
|
62
|
+
say "Kiso installed!", :green
|
|
63
|
+
say ""
|
|
64
|
+
say " Initializer: config/initializers/kiso.rb"
|
|
65
|
+
say " Design System: DESIGN_SYSTEM.md" if @design_system_created
|
|
66
|
+
say ""
|
|
67
|
+
say "Next steps:"
|
|
68
|
+
say " 1. Add Kiso's CSS to your Tailwind stylesheet:"
|
|
69
|
+
say ' @import "../builds/tailwind/kiso";'
|
|
70
|
+
say " 2. Add the theme script to your layout <head>:"
|
|
71
|
+
say " <%%= kiso_theme_script %>"
|
|
72
|
+
say " 3. Customize your brand colors in your Tailwind @theme block."
|
|
73
|
+
say " See: https://kisoui.com/guide/css-variables"
|
|
74
|
+
say ""
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def resolve_app_name
|
|
80
|
+
return options[:app_name] if options[:app_name].present?
|
|
81
|
+
return "My App" if options[:skip_design_system] == false
|
|
82
|
+
|
|
83
|
+
response = ask(<<~PROMPT)
|
|
84
|
+
What's your app called? This is just a friendly name for the document
|
|
85
|
+
header (e.g. "Outport", "My App"). [default: My App]
|
|
86
|
+
PROMPT
|
|
87
|
+
response.presence || "My App"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# <%= @app_name %> Design System
|
|
2
|
+
|
|
3
|
+
Built on [Kiso UI](https://kisoui.com). Reference this document before
|
|
4
|
+
building any UI — it defines the visual conventions that keep
|
|
5
|
+
<%= @app_name %> consistent.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Color Palette
|
|
10
|
+
|
|
11
|
+
<%= @app_name %> uses Kiso's semantic color tokens. Components reference
|
|
12
|
+
tokens like `bg-primary` and `text-foreground` — never raw palette shades.
|
|
13
|
+
|
|
14
|
+
| Token | Purpose |
|
|
15
|
+
|-------|---------|
|
|
16
|
+
| `primary` | Brand color, primary actions |
|
|
17
|
+
| `secondary` | Secondary actions |
|
|
18
|
+
| `success` | Positive feedback, confirmations |
|
|
19
|
+
| `info` | Informational messages |
|
|
20
|
+
| `warning` | Caution, non-destructive alerts |
|
|
21
|
+
| `error` | Errors, destructive actions |
|
|
22
|
+
| `neutral` | Default, non-colored UI |
|
|
23
|
+
|
|
24
|
+
Every color has a `-foreground` companion for accessible text:
|
|
25
|
+
`bg-primary text-primary-foreground`.
|
|
26
|
+
|
|
27
|
+
**Customize your brand colors** in your Tailwind stylesheet:
|
|
28
|
+
|
|
29
|
+
```css
|
|
30
|
+
@theme {
|
|
31
|
+
--color-primary: var(--color-violet-600);
|
|
32
|
+
--color-primary-foreground: var(--color-white);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
See the full list of overridable tokens:
|
|
37
|
+
[CSS Variables Reference](https://kisoui.com/guide/css-variables)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Typography Hierarchy
|
|
42
|
+
|
|
43
|
+
| Role | Classes | When to use |
|
|
44
|
+
|------|---------|-------------|
|
|
45
|
+
| Page title | `text-lg font-semibold` | Top-level page headings |
|
|
46
|
+
| Section title | `text-base font-semibold` | Section headings within a page |
|
|
47
|
+
| Card title | `text-sm font-semibold` | Card and dialog titles |
|
|
48
|
+
| Body | `text-sm` | Body text, descriptions, menu items |
|
|
49
|
+
| Caption | `text-xs` | Timestamps, counts, helper text, badges |
|
|
50
|
+
| Label | `text-sm font-medium` | Form labels, button text |
|
|
51
|
+
|
|
52
|
+
**Rules:**
|
|
53
|
+
- Never go below `text-xs` (12px)
|
|
54
|
+
- `font-semibold` for primary headings, `font-medium` for interactive
|
|
55
|
+
elements, default weight for body text
|
|
56
|
+
- Inputs use `text-base md:text-sm` (larger on mobile for zoom prevention)
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Spacing Scale
|
|
61
|
+
|
|
62
|
+
### Interactive Element Heights
|
|
63
|
+
|
|
64
|
+
| Size | Class | Examples |
|
|
65
|
+
|------|-------|----------|
|
|
66
|
+
| xs | `h-7` | Icon buttons, compact actions |
|
|
67
|
+
| sm | `h-8` | Small buttons, small inputs |
|
|
68
|
+
| md (default) | `h-9` | Buttons, inputs, selects |
|
|
69
|
+
| lg | `h-10` | Large buttons |
|
|
70
|
+
| xl | `h-11` | Extra-large buttons |
|
|
71
|
+
|
|
72
|
+
### Padding
|
|
73
|
+
|
|
74
|
+
| Context | Classes | Examples |
|
|
75
|
+
|---------|---------|----------|
|
|
76
|
+
| Interactive (default) | `px-3 py-2` | Buttons, inputs |
|
|
77
|
+
| Interactive (small) | `px-3 py-1.5` | Small buttons |
|
|
78
|
+
| Interactive (compact) | `px-2 py-1` | Extra-small buttons |
|
|
79
|
+
| Menu items | `px-2 py-1.5` | Dropdown, select, command items |
|
|
80
|
+
| Large containers | `p-6` | Card, Dialog |
|
|
81
|
+
| Medium containers | `p-4` | Popover, Sheet header |
|
|
82
|
+
| Compact containers | `p-2` | Sidebar sections |
|
|
83
|
+
|
|
84
|
+
### Gaps
|
|
85
|
+
|
|
86
|
+
| Class | When to use |
|
|
87
|
+
|-------|-------------|
|
|
88
|
+
| `gap-1` | Tight lists — sidebar menus, accordion items |
|
|
89
|
+
| `gap-1.5` | Between small elements — breadcrumb items |
|
|
90
|
+
| `gap-2` | **Default.** Icon + text, label + control, most siblings |
|
|
91
|
+
| `gap-3` | Radio/checkbox groups, form field spacing |
|
|
92
|
+
| `gap-4` | Between major sections inside a container |
|
|
93
|
+
| `gap-6` | Top-level container divisions (card header/content/footer) |
|
|
94
|
+
|
|
95
|
+
### Border Radius
|
|
96
|
+
|
|
97
|
+
Controlled by the `--kiso-radius` CSS variable. Override it to shift the
|
|
98
|
+
entire scale:
|
|
99
|
+
|
|
100
|
+
```css
|
|
101
|
+
@theme {
|
|
102
|
+
--kiso-radius: 0.375rem; /* rounder */
|
|
103
|
+
--kiso-radius: 0; /* sharp, no rounding */
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Or use a preset in `config/initializers/kiso.rb`:
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
config.apply_preset(:rounded) # buttons → rounded-full, cards → rounded-2xl
|
|
111
|
+
config.apply_preset(:sharp) # minimal rounding everywhere
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Component Conventions
|
|
117
|
+
|
|
118
|
+
Use `kui()` components instead of raw HTML. Components handle styling,
|
|
119
|
+
dark mode, accessibility, and consistent structure.
|
|
120
|
+
|
|
121
|
+
### Page structure
|
|
122
|
+
|
|
123
|
+
```erb
|
|
124
|
+
<%%= kui(:app) do %>
|
|
125
|
+
<%%= kui(:header) { "..." } %>
|
|
126
|
+
<%%= kui(:main) do %>
|
|
127
|
+
<%%= kui(:container) do %>
|
|
128
|
+
<%%= yield %>
|
|
129
|
+
<%% end %>
|
|
130
|
+
<%% end %>
|
|
131
|
+
<%%= kui(:footer) { "..." } %>
|
|
132
|
+
<%% end %>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Content cards
|
|
136
|
+
|
|
137
|
+
```erb
|
|
138
|
+
<%%= kui(:card) do %>
|
|
139
|
+
<%%= kui(:card, :header) do %>
|
|
140
|
+
<%%= kui(:card, :title) { "Title" } %>
|
|
141
|
+
<%%= kui(:card, :description) { "Description" } %>
|
|
142
|
+
<%% end %>
|
|
143
|
+
<%%= kui(:card, :content) { "..." } %>
|
|
144
|
+
<%%= kui(:card, :footer) { "..." } %>
|
|
145
|
+
<%% end %>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Forms
|
|
149
|
+
|
|
150
|
+
```erb
|
|
151
|
+
<%%= kui(:field_group) do %>
|
|
152
|
+
<%%= kui(:field) do %>
|
|
153
|
+
<%%= kui(:field, :label) { "Email" } %>
|
|
154
|
+
<%%= kui(:input, name: "email", type: "email") %>
|
|
155
|
+
<%%= kui(:field, :description) { "We'll never share your email." } %>
|
|
156
|
+
<%% end %>
|
|
157
|
+
<%%= kui(:field) do %>
|
|
158
|
+
<%%= kui(:field, :label) { "Password" } %>
|
|
159
|
+
<%%= kui(:input, name: "password", type: "password") %>
|
|
160
|
+
<%% end %>
|
|
161
|
+
<%% end %>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Empty states
|
|
165
|
+
|
|
166
|
+
```erb
|
|
167
|
+
<%%= kui(:empty, icon: "inbox", title: "No messages", description: "...") %>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Feedback
|
|
171
|
+
|
|
172
|
+
```erb
|
|
173
|
+
<%%= kui(:alert, color: :success) do %>
|
|
174
|
+
<%%= kui(:alert, :title) { "Saved" } %>
|
|
175
|
+
<%%= kui(:alert, :description) { "Your changes have been saved." } %>
|
|
176
|
+
<%% end %>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Anti-patterns
|
|
182
|
+
|
|
183
|
+
| Don't | Do instead |
|
|
184
|
+
|-------|------------|
|
|
185
|
+
| Raw `<div>`, `<button>`, `<input>` HTML | Use `kui(:card)`, `kui(:button)`, `kui(:input)` |
|
|
186
|
+
| Arbitrary spacing (`p-[13px]`, `gap-5`) | Use the documented spacing scale |
|
|
187
|
+
| Raw color classes (`bg-blue-500`, `text-zinc-600`) | Use semantic tokens (`bg-primary`, `text-muted-foreground`) |
|
|
188
|
+
| Tailwind `dark:` prefixes | Kiso handles dark mode via CSS variable swapping |
|
|
189
|
+
| Inline styles for layout | Use Tailwind utilities from the spacing scale |
|
|
190
|
+
| Custom font sizes (`text-[11px]`) | Use `text-xs`, `text-sm`, `text-base`, `text-lg` |
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Kiso.configure do |config|
|
|
4
|
+
# --- Style Preset ---
|
|
5
|
+
# Apply a pre-built style preset. Presets adjust border-radius, padding,
|
|
6
|
+
# and other visual properties across all components.
|
|
7
|
+
#
|
|
8
|
+
# Available presets:
|
|
9
|
+
# :rounded — softer corners (buttons → rounded-full, cards → rounded-2xl)
|
|
10
|
+
# :sharp — minimal rounding (buttons → rounded-sm, cards → rounded-lg)
|
|
11
|
+
#
|
|
12
|
+
# config.apply_preset(:rounded)
|
|
13
|
+
|
|
14
|
+
# --- Global Theme Overrides ---
|
|
15
|
+
# Override component styles globally. These apply to every instance of the
|
|
16
|
+
# component — use css_classes: on individual calls for one-off overrides.
|
|
17
|
+
#
|
|
18
|
+
# Accepts: base:, variants:, compound_variants:, defaults:, ui:
|
|
19
|
+
#
|
|
20
|
+
# config.theme[:button] = { base: "rounded-full" }
|
|
21
|
+
# config.theme[:card] = { base: "rounded-xl shadow-lg" }
|
|
22
|
+
# config.theme[:badge] = { defaults: { variant: :outline } }
|
|
23
|
+
#
|
|
24
|
+
# Override inner sub-part elements with ui:
|
|
25
|
+
# config.theme[:card] = { ui: { header: "p-8", footer: "px-8" } }
|
|
26
|
+
|
|
27
|
+
# --- Icon Customization ---
|
|
28
|
+
# Swap default component icons. Keys are semantic names, values are icon
|
|
29
|
+
# identifiers passed to kiso_icon (e.g. "heroicons:chevron-right").
|
|
30
|
+
#
|
|
31
|
+
# config.icons[:chevron_right] = "heroicons:chevron-right"
|
|
32
|
+
# config.icons[:x] = "heroicons:x-mark"
|
|
33
|
+
# config.icons[:search] = "heroicons:magnifying-glass"
|
|
34
|
+
|
|
35
|
+
# --- App Theme ---
|
|
36
|
+
# Theme directory for appui() components. Themes live in app/themes/<name>/.
|
|
37
|
+
# Default: :default (app/themes/default/)
|
|
38
|
+
#
|
|
39
|
+
# config.app_theme = :default
|
|
40
|
+
end
|
data/lib/kiso/cli/make.rb
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Generates scaffolding for new Kiso components.
|
|
3
|
+
# Generates scaffolding for new Kiso engine components.
|
|
4
4
|
#
|
|
5
|
-
# Creates theme module, ERB partial, Lookbook preview, and
|
|
6
|
-
#
|
|
5
|
+
# Creates theme module, ERB partial, Lookbook preview templates, and
|
|
6
|
+
# updates +lib/kiso.rb+ requires and skill reference docs.
|
|
7
|
+
#
|
|
8
|
+
# This is the CLI equivalent of +kiso:framework_component+ Rails generator,
|
|
9
|
+
# but intended for quick use without loading the Rails environment.
|
|
7
10
|
#
|
|
8
11
|
# @example
|
|
9
12
|
# $ bin/kiso make component alert
|
data/lib/kiso/cli.rb
CHANGED
|
@@ -4,6 +4,16 @@ require "thor"
|
|
|
4
4
|
require "active_support/core_ext/string/inflections"
|
|
5
5
|
|
|
6
6
|
module Kiso
|
|
7
|
+
# Command-line interface for the Kiso gem, invoked via +bin/kiso+.
|
|
8
|
+
#
|
|
9
|
+
# Routes to subcommands:
|
|
10
|
+
# - +kiso icons+ -- icon set management (delegated to kiso-icons gem)
|
|
11
|
+
# - +kiso make+ -- component scaffolding
|
|
12
|
+
# - +kiso version+ -- print gem version
|
|
13
|
+
#
|
|
14
|
+
# @see Cli::Main the top-level entry point
|
|
15
|
+
# @see Cli::Make component generator subcommand
|
|
16
|
+
# @see Cli::Icons icon management subcommand
|
|
7
17
|
module Cli
|
|
8
18
|
end
|
|
9
19
|
end
|
data/lib/kiso/color_utils.rb
CHANGED
|
@@ -1,16 +1,39 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Kiso
|
|
4
|
+
# Utility methods for color calculations, used by the Avatar component
|
|
5
|
+
# for automatic contrast text color on arbitrary background colors.
|
|
6
|
+
#
|
|
7
|
+
# @see Configuration#contrast_threshold
|
|
4
8
|
module ColorUtils
|
|
5
9
|
module_function
|
|
6
10
|
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
# Default luminance threshold for the contrast calculation.
|
|
12
|
+
# 0.42 is a perceptual midpoint per Lea Verou's research that produces
|
|
13
|
+
# better results on saturated chromatic colors than the WCAG mathematical
|
|
14
|
+
# midpoint of 0.179.
|
|
15
|
+
DEFAULT_CONTRAST_THRESHOLD = 0.42
|
|
16
|
+
|
|
17
|
+
# Returns the optimal text color ("white" or "black") for a given
|
|
18
|
+
# background color, based on WCAG relative luminance.
|
|
19
|
+
#
|
|
20
|
+
# Uses a perceptual threshold (default 0.42) rather than the
|
|
21
|
+
# mathematical midpoint of 0.179, per Lea Verou's research on
|
|
22
|
+
# contrast color generation. The higher threshold produces better
|
|
23
|
+
# results on saturated chromatic colors (e.g. Tailwind 500-shade
|
|
24
|
+
# palette).
|
|
25
|
+
#
|
|
26
|
+
# @param hex [String] a hex color string, 3-digit (#abc) or 6-digit (#aabbcc)
|
|
27
|
+
# @param threshold [Float, nil] luminance threshold override; defaults to
|
|
28
|
+
# {Configuration#contrast_threshold}
|
|
29
|
+
# @return [String] "white" or "black"
|
|
30
|
+
#
|
|
31
|
+
# @example
|
|
32
|
+
# ColorUtils.contrast_text_color("#3b82f6") # => "white"
|
|
33
|
+
# ColorUtils.contrast_text_color("#fbbf24") # => "black"
|
|
34
|
+
def contrast_text_color(hex, threshold: nil)
|
|
35
|
+
threshold ||= Kiso.config.contrast_threshold
|
|
36
|
+
|
|
14
37
|
hex = hex.delete("#")
|
|
15
38
|
hex = hex.chars.map { |c| c * 2 }.join if hex.length == 3
|
|
16
39
|
|
|
@@ -19,7 +42,7 @@ module Kiso
|
|
|
19
42
|
(c <= 0.04045) ? c / 12.92 : ((c + 0.055) / 1.055)**2.4
|
|
20
43
|
}.then { |lr, lg, lb| 0.2126 * lr + 0.7152 * lg + 0.0722 * lb }
|
|
21
44
|
|
|
22
|
-
(luminance >
|
|
45
|
+
(luminance > threshold) ? "black" : "white"
|
|
23
46
|
end
|
|
24
47
|
end
|
|
25
48
|
end
|
data/lib/kiso/configuration.rb
CHANGED
|
@@ -33,10 +33,21 @@ module Kiso
|
|
|
33
33
|
# end
|
|
34
34
|
attr_accessor :app_theme
|
|
35
35
|
|
|
36
|
+
# @return [Float] luminance threshold for contrast text color calculation.
|
|
37
|
+
# Colors with luminance above this value get black text, below get white.
|
|
38
|
+
# Default is 0.42 (perceptual midpoint per Lea Verou's research).
|
|
39
|
+
#
|
|
40
|
+
# @example Tune for a darker palette
|
|
41
|
+
# Kiso.configure do |config|
|
|
42
|
+
# config.contrast_threshold = 0.36
|
|
43
|
+
# end
|
|
44
|
+
attr_accessor :contrast_threshold
|
|
45
|
+
|
|
36
46
|
def initialize
|
|
37
47
|
@icons = default_icons
|
|
38
48
|
@theme = {}
|
|
39
49
|
@app_theme = :default
|
|
50
|
+
@contrast_threshold = Kiso::ColorUtils::DEFAULT_CONTRAST_THRESHOLD
|
|
40
51
|
end
|
|
41
52
|
|
|
42
53
|
# Resolves the active app theme directory path relative to the given root.
|