CONTRIBUTING
Contributing to Selkie::UI
Getting Started
# Clone the repository
git clone https://github.com/FCO/Selkie-UI.git
cd Selkie-UI
# Install dependencies
zef install --/test --deps-only .
# Run tests
zef test .
# Install for development
zef install .Project Structure
lib/Selkie/UI.rakumod # Main entry point ā exports all builders and helpers
lib/Selkie/UI/ # Builder modules (one per widget type)
lib/Selkie/UI/Base.rakumod # Base class for all builders
lib/Selkie/UI/Helpers.rakumod # Dynamic variable context helpers
t/ # Test files (01-*.rakutest to 05-*.rakutest)
examples/ # Runnable example scripts
dist.ini # Dist::Ini build configuration
META6.json # Raku distribution metadataDevelopment Workflow
Fork the repository
Create a feature branch
Make your changes
Run
zef test .to verify nothing is brokenSubmit a pull request
Code Conventions
Builder Pattern
Every widget gets a builder class that extends Selkie::UI::Base. Builders wrap an
underlying Selkie widget object (accessible via .obj) and expose chainable setters:
method label(Str $label) {
$.obj.label = $label;
self
}Method Chaining
All builder methods return self to enable fluent chaining:
Button.label("Click").on-press({ ... }).size(10)Reactive Setters
Builder methods use multi dispatch to support both direct values and reactive blocks:
multi method label(Str $label) { $.obj.label = $label; self }
multi method label(&label) {
my @*UI-PATHS;
with &label.() -> $value {
$.obj.label = $value;
$.auto-subscribe("label", &label);
}
self
}Dynamic Variables
Context is passed through dynamic variables that only exist within builder scopes:
$*UI-APPā The running application$*UI-PARENTā The parent builder@*UI-PATHSā Tracks state paths read during block evaluation@*UI-NODESā Nodes created by child builders
Naming
Builder classes:
Selkie::UI::<WidgetName>BuilderExported subs: PascalCase matching the widget name (e.g.,
Button,VBox)Test files: numbered
01-category.rakutestto05-category.rakutest
Testing
Tests use Raku's built-in Test module along with Selkie::Test::Keys and
Selkie::Test::Focus helper modules from the Selkie framework:
use Test;
use Selkie::UI;
use Selkie::Test::Keys;
use Selkie::Test::Focus;
subtest 'Button builder with string label' => {
my $btn = Button.label: 'Click Me';
ok $btn ~~ Selkie::UI::ButtonBuilder, 'Button builder works';
is $btn.obj.label, 'Click Me', 'Label set correctly';
}Test files are organized by widget category:
01-button-textinput.rakutestā Button and TextInput builders02-layout-structure.rakutestā Layout containers and Screen03-text-stream-collection.rakutestā Text, lists, and overlays04-data-visualization.rakutestā Chart builders05-system-helpers.rakutestā Helpers, state, and advanced widgets
Documentation
POD: Use Raku Pod6 (
=begin pod/=end pod) in.rakumodfiles for inline API documentationRakudoc: The
dist.iniusesReadmeFromPodto generate the README fromlib/Selkie/UI.rakudocAGENTS.md: Documents project commands, structure, and patterns for AI agents
Keep documentation concise and focused on usage, not implementation details