### Install Project Dependencies Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/contributing.md Commands to install project dependencies using pnpm (recommended) or npm. ```sh pnpm install ``` ```sh npm install ``` -------------------------------- ### Run Initial Project Tests Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/contributing.md Commands to run initial tests to ensure everything is passing after setup. ```sh pnpm test ``` ```sh pnpm run test ``` -------------------------------- ### Running Local Arto Example Applications Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/local-dev.md Command to start a local development server for an example application, such as the React example, allowing immediate testing of local Arto library changes due to pnpm workspace symlinks. ```bash pnpm --filter "./examples/react" dev ``` -------------------------------- ### Install common peer dependencies for Arto usage Source: https://github.com/hamidelgendy/arto/blob/main/docs/getting-started/installation.md Illustrates how to install common peer dependencies, such as React and React DOM, which may be required when integrating Arto with specific frameworks, despite Arto having no strict peer dependencies. ```bash pnpm install react react-dom ``` -------------------------------- ### Install Arto library with pnpm, npm, or yarn Source: https://github.com/hamidelgendy/arto/blob/main/docs/getting-started/installation.md Provides commands to add the Arto library to your project using popular JavaScript package managers: pnpm, npm, and yarn. Arto is framework-agnostic. ```bash pnpm add arto ``` ```bash npm install arto ``` ```bash yarn add arto ``` -------------------------------- ### Import Arto into JavaScript and TypeScript files Source: https://github.com/hamidelgendy/arto/blob/main/docs/getting-started/installation.md Shows how to import the main 'arto' function and its associated TypeScript types ('ClassName', 'Plugin') into your project after the library has been installed. ```ts import { arto } from 'arto' // or, for TypeScript: import type { ClassName, Plugin } from 'arto' ``` -------------------------------- ### Cloning and Installing Arto Monorepo Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/local-dev.md Instructions to clone the Arto repository and install its dependencies using pnpm, which handles package management for all sub-packages in the workspace. ```bash git clone https://github.com//arto.git cd arto pnpm install ``` -------------------------------- ### Example Conventional Commit Message Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/contributing.md An example of a commit message adhering to the Conventional Commits specification for clear history. ```sh feat(rules): add new 'implies' operator for advanced logic ``` -------------------------------- ### Run Documentation Server Locally Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/contributing.md Command to spin up a local VitePress server for previewing documentation changes live. ```sh pnpm docs:dev ``` -------------------------------- ### Arto: Good Example - Declaring Config Once for Performance Source: https://github.com/hamidelgendy/arto/blob/main/docs/advanced/performance.md Illustrates the recommended practice of declaring and initializing an Arto configuration outside of a React component's render function, or memoizing it, to ensure the setup cost is paid only once. This optimizes performance by preventing repeated configuration initialization. ```tsx type Variants = { size: 'small' | 'large' theme: 'primary' | 'secondary' } const buttonConfig = arto({ className: 'inline-flex items-center rounded', variants: { size: { small: 'px-2 py-1 text-sm', large: 'px-4 py-2 text-lg', }, theme: { primary: 'bg-blue-500 text-white', secondary: 'bg-gray-300 text-gray-800', }, }, }) function GoodButtonComponent({ size, theme }) { const className = buttonConfig({ variants: { size, theme } }) return } ``` -------------------------------- ### Install Arto with pnpm Source: https://github.com/hamidelgendy/arto/blob/main/packages/arto/README.md This snippet shows how to install the Arto library using the pnpm package manager. Arto is a lightweight, framework-agnostic library for managing CSS class names, compatible with various UI frameworks and CSS strategies. ```bash pnpm add arto ``` -------------------------------- ### Running Local Arto Documentation Server Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/local-dev.md Command to start the VitePress development server for the Arto documentation, enabling live preview and hot-reloading of changes made to markdown files. ```bash pnpm docs:dev ``` -------------------------------- ### Install Arto with pnpm Source: https://github.com/hamidelgendy/arto/blob/main/README.md This snippet shows how to add the Arto library to your project using the pnpm package manager. ```bash pnpm add arto ``` -------------------------------- ### Lint and Format Code with pnpm Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/contributing.md Commands to lint and format code using ESLint and Prettier to maintain consistent style before committing. ```sh pnpm lint ``` ```sh pnpm lint:fix ``` ```sh pnpm format ``` -------------------------------- ### Create or Update a Changeset Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/contributing.md Command to create or update a Changeset, which is used for versioning and managing releases. ```sh pnpm changeset ``` -------------------------------- ### Arto: Simplified ClassName Definition Example Source: https://github.com/hamidelgendy/arto/blob/main/docs/advanced/performance.md A better example demonstrating a simplified `className` definition in Arto, using a single string or a flat array. This reduces the overhead associated with flattening complex nested structures during class generation, improving performance. ```ts const simplerConfig = arto({ className: 'base-class another-class some-other-class', }) ``` -------------------------------- ### Basic Arto Usage with Variants and States Source: https://github.com/hamidelgendy/arto/blob/main/README.md This simplified example demonstrates how to create an Arto instance, define basic class names, variants (size), and states (disabled), and then generate a final class string based on selected options. ```ts import { arto } from 'arto' // 1. Create an arto instance with basic config const myArto = arto({ // Always include these classes className: 'btn', // Define variants for styling variants: { size: { small: 'btn-sm', large: 'btn-lg', }, }, // Define states for toggling states: { disabled: 'opacity-50 pointer-events-none', }, }) // 2. Generate a final class string const classString = myArto({ variants: { size: 'large' }, states: { disabled: true }, }) // => "btn btn-lg opacity-50 pointer-events-none" ``` -------------------------------- ### Run Vitest Tests During Development Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/contributing.md Command to run Vitest tests to ensure changes pass existing tests and to verify new ones. ```sh pnpm test ``` -------------------------------- ### Complete Arto Configuration Example with Variants and States Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/variants-states-types.md This comprehensive example demonstrates how to integrate `VariantOptions` and `StatesOptions` within a full `arto` configuration. It showcases defining a 'shadow' variant with different values, applying base classes, nesting states (like 'hover'), and using `dependsOn` for conditional state application, illustrating the power of Arto's flexible styling system. ```ts import { arto } from 'arto' const cardConfig = arto({ className: 'transition-shadow border rounded-md', variants: { shadow: { none: 'shadow-none', small: { className: 'shadow-sm', states: { hover: { className: 'shadow-md', dependsOn: ['hover', { not: ['disabled'] }], }, }, }, large: { className: 'shadow-lg', states: { hover: 'shadow-xl', }, }, }, }, states: { disabled: 'opacity-60 pointer-events-none', }, }) // If user picks shadow=small and hover + not disabled => "shadow-md" ``` -------------------------------- ### Arto Rule Basic Structure Example Source: https://github.com/hamidelgendy/arto/blob/main/docs/core-concepts/rules.md This snippet demonstrates the fundamental structure of an Arto rule within the configuration. It shows how to define conditions using `when` for variants and states, and then specify classes to `remove` or `add` when those conditions are met. The example illustrates removing a variant's classes and adding new ones when a specific theme and state combination is active. ```ts import { arto } from 'arto' type Variants = { theme: 'primary' | 'secondary' } type States = 'hover' | 'pressed' const configWithRules = arto({ className: 'btn', variants: { theme: { primary: 'bg-blue-500 text-white', secondary: 'bg-gray-300 text-gray-800', }, }, states: { hover: 'shadow-md', pressed: 'scale-95', }, rules: [ { when: { variants: { theme: ['primary'] }, states: ['pressed'], }, remove: { variants: ['theme'], }, add: 'bg-blue-700 text-white', } ] }) ``` -------------------------------- ### Combine Arto Configuration with States Source: https://github.com/hamidelgendy/arto/blob/main/docs/getting-started/basic-usage.md This example extends the basic Arto configuration to include states, specifically a `disabled` state. It shows how to define states within the configuration and then apply them when generating class names, demonstrating how state-specific classes are appended. ```ts import { arto } from 'arto' type Variants = { size: 'small' | 'large' theme: 'primary' | 'secondary' } type States = 'disabled' const buttonWithState = arto({ className: 'inline-flex items-center font-medium transition-colors ease-in-out', variants: { size: { small: 'px-2 py-1 text-sm', large: 'px-4 py-2 text-base', }, theme: { primary: 'bg-blue-500 text-white', secondary: 'bg-gray-100 text-gray-800', }, }, states: { disabled: 'opacity-50 pointer-events-none', }, }) // Now call the config with states: const result = buttonWithState({ variants: { size: 'small', theme: 'primary' }, states: { disabled: true }, }) console.log(result) // => "inline-flex items-center font-medium transition-colors ease-in-out px-2 py-1 text-sm bg-blue-500 text-white opacity-50 pointer-events-none" ``` -------------------------------- ### Basic Arto Instance Configuration and Class Generation Source: https://github.com/hamidelgendy/arto/blob/main/packages/arto/README.md This example demonstrates the fundamental usage of Arto, showing how to create an instance with base class names, define variants (e.g., size), and states (e.g., disabled). It then illustrates how to generate a final class string by applying specific variants and states, resulting in a combined CSS class string. ```ts import { arto } from 'arto' // 1. Create an arto instance with basic config const myArto = arto({ // Always include these classes className: 'btn', // Define variants for styling variants: { size: { small: 'btn-sm', large: 'btn-lg' } }, // Define states for toggling states: { disabled: 'opacity-50 pointer-events-none' } }) // 2. Generate a final class string const classString = myArto({ variants: { size: 'large' }, states: { disabled: true } }) // => "btn btn-lg opacity-50 pointer-events-none" ``` -------------------------------- ### Generate Class Names from Arto Configuration Source: https://github.com/hamidelgendy/arto/blob/main/docs/getting-started/basic-usage.md After defining an Arto configuration, this example shows how to call the configuration function with desired variants to generate a final, space-joined string of Tailwind classes. It demonstrates how Arto merges base, variant, and theme classes. ```ts // Usage example: const result = buttonConfig({ variants: { size: 'small', theme: 'secondary' }, }) console.log(result) // => "inline-flex items-center font-medium transition-colors ease-in-out px-2 py-1 text-sm bg-gray-100 text-gray-800" ``` -------------------------------- ### Arto className Nested Arrays and Callbacks Example Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/classname.md Shows an example of `className` with deeply nested arrays and callbacks, highlighting Arto's ability to flatten all levels and process functions with the provided context. ```ts import { arto } from 'arto' const nestedConfig = arto({ className: [ 'btn', ['font-semibold', 'transition-colors'], (ctx) => (ctx?.active ? 'shadow-md' : 'shadow-none'), ], }) const result = nestedConfig({ context: { active: true } }) // => "btn font-semibold transition-colors shadow-md" ``` -------------------------------- ### Advanced Arto Configuration with Nested States and Context Source: https://github.com/hamidelgendy/arto/blob/main/packages/arto/README.md This advanced example showcases complex Arto features, including type definitions for variants, states, and context. It demonstrates nested state definitions with 'dependsOn' logic, callback-based class names that utilize user-defined context, and conditional class application through a rules array. The snippet also provides usage examples illustrating different combinations of variants, states, and context. ```ts import { arto } from 'arto' // Define variant keys and possible values type Variants = { intent: 'info' | 'danger' | 'success' size: 'sm' | 'md' } // Define possible states type States = 'hovered' | 'disabled' // Optional context data passed during class generation type Context = { username: string } const myArto = arto({ // Base classes className: 'base', // Variant definitions variants: { intent: { info: 'intent-info', danger: { className: 'intent-danger', states: { hovered: { className: 'intent-danger-hovered', dependsOn: [{ not: ['disabled'] }] // apply only if 'disabled' is not active } } }, // Callback-based class name success: (ctx) => (ctx?.username === 'admin' ? 'intent-success-admin' : 'intent-success') }, size: { sm: 'size-sm', md: 'md' } }, // Global states states: { hovered: { className: 'global-hovered', dependsOn: [{ not: ['disabled'] }] // can't hover if disabled }, disabled: 'global-disabled' }, // Advanced rules rules: [ { when: { variants: { intent: ['info', 'danger'] }, states: ['hovered'], logic: 'AND' }, add: 'rule-class' } ] }) // Usage examples: // A) Info + small (no states) const exampleA = myArto({ variants: { intent: 'info', size: 'sm' } }) // => "base rule-class intent-info size-sm" // B) Danger + hovered + disabled const exampleB = myArto({ variants: { intent: 'danger', size: 'sm' }, states: { hovered: true, disabled: true } }) // => "base rule-class intent-danger size-sm global-disabled" // C) Success + hovered, with admin context const exampleC = myArto({ variants: { intent: 'success', size: 'md' }, states: { hovered: true }, context: { username: 'admin' } }) // => "base intent-success-admin size-md global-hovered" ``` -------------------------------- ### Create a New Git Branch Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/contributing.md Command to create a dedicated Git branch for new features or fixes, branching off the `main` branch. ```sh git checkout -b feature/my-new-feature ``` -------------------------------- ### Arto: Overly Nested ClassName Definition Example Source: https://github.com/hamidelgendy/arto/blob/main/docs/advanced/performance.md An example of an Arto configuration with an overly nested `className` definition, including arrays and callbacks. While Arto can flatten these, simplifying the structure reduces overhead during class generation. ```ts const nestedConfig = arto({ className: ['base-class', ['another-class', () => ['maybe-this-class']], 'some-other-class'], }) ``` -------------------------------- ### Implement a Custom Arto Plugin Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/plugin-interface.md This example demonstrates how to create a custom Arto plugin named `MyExamplePlugin`. It defines a unique `id`, sets its `stage` to `'core'` for execution alongside built-in plugins, and assigns an `order` for priority. The `apply` method uses `builder.addPostCoreCallback` to log the current classes after core logic completes but before 'after' stage plugins run, showcasing how to interact with the `ClassNameBuilder`. ```ts import type { Plugin } from 'arto' export const MyExamplePlugin: Plugin = { id: 'my/example-plugin', stage: 'core', order: 5, apply(builder) { // Run logic at the 'core' stage with priority 5 builder.addPostCoreCallback(() => { // Possibly do something with the final classes const allClasses = builder.getAllClasses() console.log('[MyExamplePlugin] Classes so far:', allClasses.join(' ')) }) } } ``` -------------------------------- ### Generate a Changeset for Package Updates Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/release-flow.md This command initiates the Changesets tool, guiding the user to select affected packages, define the type of change (major, minor, or patch), and provide a summary for the changelog. It results in a new markdown file being created in the `.changeset/` directory. ```bash pnpm changeset ``` -------------------------------- ### Defining and Using Arto Configuration for Dynamic Class Names Source: https://github.com/hamidelgendy/arto/blob/main/docs/index.md This example demonstrates how to define a configuration for a button component using Arto, specifying its variants (size, color) and states (disabled). It then shows how to use this configuration to generate a dynamic class string based on selected variants and states, centralizing styling logic. ```ts import { arto } from 'arto' type ButtonVariants = { size: 'small' | 'large' color: 'primary' | 'secondary' } type ButtonStates = 'disabled' // Define your "configuration" for the button const buttonConfig = arto({ className: 'inline-flex items-center font-medium transition ease-in-out', variants: { size: { small: 'px-2 py-1 text-sm', large: 'px-4 py-2 text-base', }, color: { primary: 'bg-blue-500 text-white border-transparent', secondary: 'bg-white text-blue-500 border-blue-500', }, }, states: { disabled: 'opacity-50 pointer-events-none', }, defaultVariants: { size: 'large', color: 'primary', }, }) // Use your config in code: const classString = buttonConfig({ variants: { size: 'small', color: 'secondary' }, states: { disabled: false }, }) // The result might be: // => "inline-flex items-center font-medium transition ease-in-out px-2 py-1 text-sm bg-white text-blue-500 border-blue-500" ``` -------------------------------- ### Arto: Bad Example - Re-initializing Config in React Component Source: https://github.com/hamidelgendy/arto/blob/main/docs/advanced/performance.md Demonstrates an anti-pattern where an Arto configuration is re-initialized on every render within a React component, leading to unnecessary overhead. This should be avoided for performance. ```tsx function BadButtonComponent({ size, theme }) { const buttonConfig = arto({ // ... }) const className = buttonConfig({ variants: { size, theme } }) return } ``` -------------------------------- ### Example Usage of VariantConfig with Nested States Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/variants-states-types.md This example demonstrates how `VariantConfig` is used within `VariantOptions` to define styles for different `size` variants. It shows how a `className` can be applied directly and how `states` can be nested to provide conditional styling (e.g., `hover` effects) that are specific to a chosen variant value. ```ts { size: { small: { className: "px-2 py-1 text-sm", states: { hover: "bg-gray-50" } }, large: { className: "px-4 py-2 text-base", states: { hover: "bg-gray-100" } } } } ``` -------------------------------- ### Arto Rule Adding Classes Example Source: https://github.com/hamidelgendy/arto/blob/main/docs/core-concepts/rules.md This example demonstrates how to use the `add` property in an Arto rule to append new classes when the rule's conditions are satisfied. It shows that classes can be added as a single string or an array of strings, allowing for flexible styling adjustments. ```ts rules: [ { when: { states: ['pressed'], }, add: [ 'bg-opacity-75', 'transform-gpu', ], }, ] ``` -------------------------------- ### Arto Plugin Example: Clear Hover State Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/classname-builder.md Demonstrates how to create an Arto plugin that interacts with the ClassNameBuilder. This example shows a 'core' stage plugin that uses a post-core callback to clear global 'hover' state classes if the 'disabled' state is also active, illustrating conditional class manipulation. ```ts import type { Plugin } from 'arto' export const ExamplePlugin: Plugin = { id: 'example/clear-hover', stage: 'core', order: 5, apply(builder) { // Remove the global 'hover' state classes if 'disabled' is active builder.addPostCoreCallback(() => { const states = builder.getActiveStates() if (states.has('disabled') && states.has('hover')) { builder.clearGlobalStateClasses('hover') } }) }, } ``` -------------------------------- ### Test Arto Configs with Context Parameters Source: https://github.com/hamidelgendy/arto/blob/main/docs/advanced/testing.md This example shows how to unit test Arto configurations that utilize the `context` parameter for dynamic class generation. It verifies that the configuration correctly applies different class sets based on the value of a `darkMode` flag passed through the context object. ```typescript const contextConfig = arto({ className: (ctx) => (ctx?.darkMode ? 'bg-black text-white' : 'bg-white text-black'), }) test('applies dark mode classes when darkMode = true', () => { const result = contextConfig({ context: { darkMode: true } }) expect(result).toContain('bg-black text-white') }) test('defaults to light mode if darkMode is false', () => { const result = contextConfig({ context: { darkMode: false } }) expect(result).toContain('bg-white text-black') }) ``` -------------------------------- ### Define and Apply Arto Styles with Variants and States (JavaScript) Source: https://github.com/hamidelgendy/arto/blob/main/packages/arto/index.html This snippet illustrates how to use the 'arto' library to create dynamic CSS classes. It defines styles with a base class, size and color variants, and a disabled state. The example then creates two buttons, applying different combinations of variants and states to each using the generated 'styles' function, and appends them to the DOM. ```JavaScript import { arto } from 'src' const styles = arto({ className: 'base-class', variants: { size: { small: 'text-sm', large: 'text-lg' }, color: { primary: 'bg-primary', secondary: 'bg-secondary' } }, states: { disabled: 'disabled' } }) // Create a couple of buttons inside #app const app = document.getElementById('app') // (1) A small, secondary button const btn1 = document.createElement('button') btn1.textContent = 'Small, Secondary' btn1.className = styles({ variants: { size: 'small', color: 'secondary' } }) app.appendChild(btn1) // (2) A large, primary & disabled button const btn2 = document.createElement('button') btn2.textContent = 'Large, Primary, Disabled' btn2.className = styles({ variants: { size: 'large', color: 'primary' }, states: { disabled: true } }) app.appendChild(btn2) ``` -------------------------------- ### Configure Arto with Rules and Custom Logic Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/rules-types.md This example demonstrates how to configure Arto with a set of rules. It includes a rule with simple 'AND' logic and another with a custom `logic` callback function that evaluates variant and state matches to dynamically apply or remove classes. ```ts const config = arto({ className: 'block', variants: { theme: { primary: 'text-white bg-blue-600', secondary: 'text-gray-700 bg-gray-100' }, }, states: { disabled: 'opacity-60 pointer-events-none' }, rules: [ { when: { variants: { theme: ['primary'] }, states: ['disabled'], logic: 'AND', // default anyway }, remove: { variants: ['theme'] }, add: 'bg-blue-300 text-white', }, { when: { variants: { theme: ['primary'] }, states: ['disabled', 'hover'], // Custom logic function logic: (meta) => { // If 'theme' is 'primary' and any state is active => apply const isPrimary = meta.variantMatches.theme const anyStateActive = Object.values(meta.stateMatches).some(Boolean) return Boolean(isPrimary) && anyStateActive }, }, remove: { base: true }, add: 'bg-purple-600 text-white', }, ], }) ``` -------------------------------- ### Defining and Applying Global and Local Arto Plugins Source: https://github.com/hamidelgendy/arto/blob/main/docs/core-concepts/plugins.md This TypeScript example demonstrates how to define both global and local plugins for the Arto framework. The `UsageAnalyticsPlugin` is registered globally via `pluginHub` to log usage across all configurations, while the `BetaFeaturePlugin` is applied locally to `myConfig` to conditionally modify variant classes based on a context flag. ```TypeScript import { type Plugin, pluginHub, arto } from 'arto' type Variants = { theme: 'dark' | 'light' } interface Context { betaFlag: boolean } // 1) Global plugin for usage analytics const UsageAnalyticsPlugin: Plugin = { id: 'analytics/global-usage', stage: 'core', apply(builder) { builder.addFinalBuildCallback(() => { const variants = builder.getSelectedVariants() const states = Array.from(builder.getActiveStates()) console.log('Analytics =>', variants, states) }) } } pluginHub.register(UsageAnalyticsPlugin) // 2) Local plugin for a single config const BetaFeaturePlugin: Plugin = { id: 'beta/local-plugin', stage: 'core', apply(builder) { builder.addPostCoreCallback(() => { const ctx = builder.getContext() if (ctx?.betaFlag) { builder.clearVariantClasses('theme') // remove theme variant classes if betaFlag is set } }) } } const myConfig = arto( { className: 'font-sans px-4 py-2', variants: { theme: { dark: 'bg-black text-white', light: 'bg-white text-black' } } }, [BetaFeaturePlugin], // local ) ``` -------------------------------- ### Advanced Arto Configuration with Nested States, Callbacks, and Rules Source: https://github.com/hamidelgendy/arto/blob/main/README.md This complex example illustrates advanced Arto features including nested state definitions with `dependsOn` logic, callback-based class names leveraging a user-defined `context`, and conditional class application through a `rules` array with logical operators. ```ts import { arto } from 'arto' // Define variant keys and possible values type Variants = { intent: 'info' | 'danger' | 'success' size: 'sm' | 'md' } // Define possible states type States = 'hovered' | 'disabled' // Optional context data passed during class generation type Context = { username: string } const myArto = arto({ // Base classes className: 'base', // Variant definitions variants: { intent: { info: 'intent-info', danger: { className: 'intent-danger', states: { hovered: { className: 'intent-danger-hovered', dependsOn: [{ not: ['disabled'] }], // apply only if 'disabled' is not active }, }, }, // Callback-based class name success: (ctx) => (ctx?.username === 'admin' ? 'intent-success-admin' : 'intent-success'), }, size: { sm: 'size-sm', md: 'md', }, }, // Global states states: { hovered: { className: 'global-hovered', dependsOn: [{ not: ['disabled'] }], // can't hover if disabled }, disabled: 'global-disabled', }, // Advanced rules rules: [ { when: { variants: { intent: ['info', 'danger'] }, states: ['hovered'], logic: 'AND', }, add: 'rule-class', }, ], }) // Usage examples: // A) Info + small (no states) const exampleA = myArto({ variants: { intent: 'info', size: 'sm' }, }) // => "base rule-class intent-info size-sm" // B) Danger + hovered + disabled const exampleB = myArto({ variants: { intent: 'danger', size: 'sm' }, states: { hovered: true, disabled: true }, }) // => "base rule-class intent-danger size-sm global-disabled" // C) Success + hovered, with admin context const exampleC = myArto({ variants: { intent: 'success', size: 'md' }, states: { hovered: true }, context: { username: 'admin' }, }) // => "base intent-success-admin size-md global-hovered" ``` -------------------------------- ### Unit Test Arto Config with Vitest/Jest Source: https://github.com/hamidelgendy/arto/blob/main/docs/advanced/testing.md This example demonstrates a fundamental unit test for an Arto configuration using Vitest or Jest. It defines a button component with various sizes and themes, then asserts that the generated class strings correctly reflect default settings and specific variant/state combinations. ```typescript import { arto } from 'arto' import { expect, test, describe } from 'vitest' describe('Button config', () => { const buttonConfig = arto({ className: 'inline-flex items-center font-medium', variants: { size: { small: 'px-2 py-1 text-sm', large: 'px-4 py-2 text-base' }, theme: { primary: 'bg-blue-500 text-white', secondary: 'bg-gray-100 text-gray-800' }, }, states: { disabled: 'opacity-50 pointer-events-none', }, defaultVariants: { size: 'large', theme: 'primary', }, }) test('default config produces "large + primary" classes', () => { const result = buttonConfig() expect(result).toContain('inline-flex') expect(result).toContain('px-4') expect(result).toContain('bg-blue-500') }) test('size=small, theme=secondary, disabled=true', () => { const result = buttonConfig({ variants: { size: 'small', theme: 'secondary' }, states: { disabled: true }, }) expect(result).toContain('px-2') // from size=small expect(result).toContain('bg-gray-100 text-gray-800') // from theme=secondary expect(result).toContain('opacity-50 pointer-events-none') // from disabled expect(result).not.toContain('bg-blue-500') }) }) ``` -------------------------------- ### Register Global Arto Plugins Source: https://github.com/hamidelgendy/arto/blob/main/docs/core-concepts/plugins.md This snippet demonstrates how to register custom plugins globally using Arto's 'pluginHub'. It shows examples of registering a single plugin or multiple plugins in a batch. Global plugins affect all subsequent Arto configurations unless explicitly unregistered. ```ts import { pluginHub } from 'arto' import { LintConflictsPlugin } from './lint-conflicts-plugin.ts' // Single plugin pluginHub.register(LintConflictsPlugin) // Or multiple pluginHub.registerBatch([ LintConflictsPlugin, // SomeOtherGlobalPlugin, ]) ``` -------------------------------- ### TypeScript Configuration for Arto Projects Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/typescript-guide.md This JSON snippet provides a recommended tsconfig.json configuration for projects using Arto, emphasizing 'strict' mode for early type issue detection. It outlines essential compiler options for module resolution and target, ensuring compatibility with Arto's type definitions without special configurations. ```json { "compilerOptions": { "strict": true, "module": "ESNext", "target": "ES2020", "moduleResolution": "Bundler", "noEmit": true }, "include": ["**/*.ts", "**/*.tsx"] } ``` -------------------------------- ### Demonstrate compile-time error detection in Arto with TypeScript Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/typescript-guide.md Illustrates how TypeScript provides immediate compile-time errors when invalid variant values are used with Arto. This highlights a key benefit of type safety, catching potential issues before code execution. ```ts // If you try something invalid: iconConfig({ variants: { // @ts-expect-error size: 'medium' // TS error: Type '"medium"' is not assignable to type 'IconSize' } }) ``` -------------------------------- ### Extend Arto variant keys with TypeScript types Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/typescript-guide.md Illustrates how to define and use custom TypeScript types for Arto variant keys and states. This approach centralizes type definitions, ensuring that `alertConfig` calls are type-checked against predefined `AlertVariants` and `AlertStates`. ```ts import { arto } from 'arto' type AlertVariants = { level: 'info' | 'warning' | 'error' size: 'small' | 'normal' | 'large' } type AlertStates = 'dismissed' | 'disabled' const alertConfig = arto({ className: 'rounded-md p-4', variants: { level: { info: 'bg-blue-100 text-blue-800', warning: 'bg-yellow-100 text-yellow-800', error: 'bg-red-100 text-red-800' }, size: { small: 'text-sm', normal: 'text-base', large: 'text-lg' } }, states: { dismissed: 'hidden', disabled: 'opacity-50 pointer-events-none' } }) ``` -------------------------------- ### Register Local Plugins with Arto Config Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/plugin-interface.md This example demonstrates how to apply plugins locally to a specific Arto configuration, rather than globally via `pluginHub`. By passing an array of plugins as the second argument to the `arto()` function, these plugins are merged with any globally registered plugins and then sorted by stage and order, ensuring they only affect the `myConfig` instance. ```ts import { arto } from 'arto' import { MyExamplePlugin } from './my-plugin' const myConfig = arto( { className: 'some-base-classes', // ... }, [MyExamplePlugin], ) ``` -------------------------------- ### Using Context in Arto States with dependsOn Source: https://github.com/hamidelgendy/arto/blob/main/docs/advanced/context.md This example illustrates how to use the `context` object within a state's `dependsOn` function. It allows conditional activation of a state (e.g., `adminMode`) based on context properties like `userIsAdmin`, ensuring states are applied only when relevant conditions are met. ```ts import { arto } from 'arto' type State = 'adminMode' interface Context { userIsAdmin: boolean adminBadgeClass: string } const stateWithContext = arto({ states: { adminMode: { className: (ctx) => ctx?.adminBadgeClass || 'bg-yellow-200 text-gray-800', dependsOn: (activeStates, ctx) => Boolean(ctx?.userIsAdmin), }, }, }) const res = stateWithContext({ states: { adminMode: true }, context: { userIsAdmin: false }, }) // Because userIsAdmin = false, "adminMode" doesn't apply even though we passed `true`. ``` -------------------------------- ### Basic Usage of Arto for Dynamic Class Generation Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/arto-function.md This example demonstrates how to define an Arto configuration for a button component, including base classes, variants (size, theme), states (disabled), default variants, and conditional rules. It then shows how to invoke the returned function to generate a final class string based on specific variant and state selections. ```ts import { arto } from 'arto' type Variants = { size: 'small' | 'large' theme: 'primary' | 'secondary' } type States = 'disabled' const buttonConfig = arto({ className: 'inline-flex items-center font-medium', variants: { size: { small: 'px-2 py-1 text-sm', large: 'px-4 py-2 text-base', }, theme: { primary: 'bg-blue-500 text-white', secondary: 'bg-gray-200 text-gray-800', }, }, states: { disabled: 'opacity-50 pointer-events-none', }, defaultVariants: { size: 'large', }, rules: [ { when: { variants: { theme: ['primary'] }, states: ['disabled'], }, remove: { variants: ['theme'] }, add: 'bg-blue-300 text-white', }, ], }) // Generate final classes const finalClasses = buttonConfig({ variants: { size: 'small', theme: 'secondary' }, states: { disabled: false }, }) console.log(finalClasses) // => "inline-flex items-center font-medium px-2 py-1 text-sm bg-gray-200 text-gray-800" ``` -------------------------------- ### Differentiate Focus and FocusVisible States with Arto Source: https://github.com/hamidelgendy/arto/blob/main/docs/advanced/accessibility.md This example illustrates how Arto can be used to apply distinct styles for 'focus' and 'focusVisible' states. It allows for minimal styling on pointer-based focus and a more prominent highlight for keyboard-based focus, aligning with modern accessibility guidelines like 'focus-visible' polyfills. ```ts const advancedFocusConfig = arto({ states: { focus: 'outline-none ring-1 ring-blue-300', focusVisible: 'ring-2 ring-offset-2 ring-blue-500' } }) const final = advancedFocusConfig({ states: { focus: true, focusVisible: false } }) // => "outline-none ring-1 ring-blue-300" ``` -------------------------------- ### Define and use typed variants, states, and context with Arto in TypeScript Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/typescript-guide.md Demonstrates how to explicitly define types for Arto variants, states, and context objects using TypeScript. It shows the `arto` function's generic parameters for type safety and how to apply these types when configuring and calling Arto, enabling autocompletion and compile-time checks. ```ts import { arto } from 'arto' // 1) Define a shape for your variants (TypeScript can infer it, but you can be explicit). type ButtonVariants = { size: 'small' | 'large' theme: 'primary' | 'secondary' } // 2) Define valid states as a union of string literals. type ButtonStates = 'disabled' | 'hover' // 3) (Optional) Provide a context type if using advanced logic or callbacks. interface ButtonContext { isDarkMode?: boolean } const buttonConfig = arto({ className: (ctx) => (ctx?.isDarkMode ? 'text-white bg-neutral-900' : 'text-black bg-neutral-100'), variants: { size: { small: 'px-2 py-1 text-sm', large: 'px-4 py-2 text-base' }, theme: { primary: 'bg-blue-500', secondary: 'bg-gray-200 text-gray-800' } }, states: { disabled: 'opacity-50 pointer-events-none', hover: 'shadow-md' } }) // Arto’s return function now expects typed variants and states: const finalClasses = buttonConfig({ variants: { size: 'small', theme: 'primary' }, states: { disabled: true, hover: false }, context: { isDarkMode: false } }) ``` -------------------------------- ### Configure Arto for Accessible Color Contrast Source: https://github.com/hamidelgendy/arto/blob/main/docs/advanced/accessibility.md This snippet demonstrates how to configure Arto to manage color contrast themes. It defines variants for 'highContrast' and 'normal' themes, applying specific background, text, and border colors to ensure WCAG compliance. The example shows how to apply the 'highContrast' variant. ```ts const contrastConfig = arto({ className: 'font-medium p-2 border', variants: { theme: { highContrast: 'bg-black text-white border-white', normal: 'bg-gray-200 text-gray-900 border-gray-400' } } }) const result = contrastConfig({ variants: { theme: 'highContrast' } }) // => "font-medium p-2 border bg-black text-white border-white" ``` -------------------------------- ### Defining a Simple Arto State Source: https://github.com/hamidelgendy/arto/blob/main/docs/core-concepts/states.md This example demonstrates how to define a single state, `disabled`, in Arto. The `states` property maps state names to their corresponding class strings. When the `disabled` state is set to `true`, Arto appends the specified classes (`opacity-50 pointer-events-none`) to the final output, centralizing conditional styling. ```ts import { arto } from 'arto' type States = 'disabled' const buttonConfig = arto({ className: 'inline-flex items-center font-medium', states: { disabled: 'opacity-50 pointer-events-none', }, }) const classes = buttonConfig({ states: { disabled: true }, }) // => "inline-flex items-center font-medium opacity-50 pointer-events-none" ``` -------------------------------- ### Arto Rule Custom Logic with AND/OR/NOT Source: https://github.com/hamidelgendy/arto/blob/main/docs/core-concepts/rules.md This example illustrates how to apply advanced boolean logic (AND, OR, NOT, XOR, IMPLIES) within the `when` condition of an Arto rule. It demonstrates using `logic.variants`, `logic.states`, and `logic.combine` to define complex conditional relationships, such as 'OR' for multiple variant values and 'AND' for combining variant and state results. ```ts rules: [ { when: { variants: { theme: ['primary', 'secondary'] }, states: ['hover', 'pressed'], logic: { variants: 'OR', states: 'OR', combine: 'AND', }, }, remove: { base: true }, add: 'bg-red-500 text-white', }, ] ``` -------------------------------- ### Defining Arto Plugin with TypeScript Types Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/typescript-guide.md This TypeScript snippet demonstrates how to define an Arto plugin with strong type checking for variants, states, and context. It shows the Plugin interface parametrization and how to access a typed context within the apply method for debug logging, ensuring no accidental references to nonexistent fields. ```ts import { Plugin, ClassNameBuilder, VariantValue } from 'arto' type MyContext = { debug?: boolean } export const MyPlugin: Plugin, string, MyContext> = { id: 'my-plugin', stage: 'after', apply(builder) { const ctx = builder.getContext() // typed as MyContext | undefined if (ctx?.debug) { console.log('[MyPlugin Debug] Classes =>', builder.getAllClasses()) } } } ``` -------------------------------- ### Example StateDependency with Array of Required and Excluded States Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/variants-states-types.md This example illustrates how to use the array form of `StateDependency` to define conditions for a state. It specifies that the associated style should only apply if the 'hover' state is active AND the 'disabled' state is NOT active, providing precise control over state-dependent styling. ```ts dependsOn: ['hover', { not: ['disabled'] }] ``` -------------------------------- ### Running Arto Unit Tests with Vitest Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/local-dev.md Commands to execute the Arto unit test suite using Vitest, including running all tests with coverage or in watch mode for real-time feedback during development. ```bash pnpm test # Runs the test suite, collecting coverage pnpm test:watch ``` -------------------------------- ### Arto className Skipping Classes with Falsey Returns Example Source: https://github.com/hamidelgendy/arto/blob/main/docs/api/classname.md Demonstrates how returning `false` or `undefined` from a `className` callback causes Arto to skip adding any classes for that part, allowing for conditional class application. ```ts import { arto } from 'arto' const skipConfig = arto({ className: (ctx) => (ctx?.disabled ? false : 'hover:bg-blue-500'), }) const result1 = skipConfig({ context: { disabled: true } }) // => "" (empty string) const result2 = skipConfig({ context: { disabled: false } }) // => "hover:bg-blue-500" ``` -------------------------------- ### Building and Watching Arto Packages Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/local-dev.md Commands to build all packages in the Arto monorepo or specific packages using pnpm filters, and to watch for changes for automatic rebuilding during local development. ```bash pnpm build # Builds all packages (including /packages/arto) pnpm watch # Watches for changes in packages and rebuilds them (useful for local dev) ``` ```bash pnpm --filter "./packages/arto" run build pnpm --filter "./packages/arto" run build --watch ``` -------------------------------- ### Create Arto Configuration for Button Component Source: https://github.com/hamidelgendy/arto/blob/main/docs/getting-started/basic-usage.md This snippet demonstrates how to create a basic Arto configuration for a button component. It defines `className` for base styles, `variants` for different sizes and themes with their respective Tailwind classes, and `defaultVariants` for fallback values. Type checking for variants is also shown. ```ts import { arto } from 'arto' // Declare variant keys/values explicitly if you want type checking: type Variants = { size: 'small' | 'large' theme: 'primary' | 'secondary' } // Create your button configuration const buttonConfig = arto({ className: 'inline-flex items-center font-medium transition-colors ease-in-out', variants: { size: { small: 'px-2 py-1 text-sm', large: 'px-4 py-2 text-base', }, theme: { primary: 'bg-blue-500 text-white', secondary: 'bg-gray-100 text-gray-800', }, }, defaultVariants: { size: 'large', theme: 'primary', }, }) ``` -------------------------------- ### Build and Test Project After Versioning Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/release-flow.md After package versions have been bumped, these commands ensure that the entire project can still be successfully built and that all tests pass. This step is critical for verifying the integrity and functionality of the codebase with the new version numbers before committing. ```bash pnpm build pnpm test ``` -------------------------------- ### Commit and Push Version Bump and Changelog Updates Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/release-flow.md Once the versioning, building, and testing steps are complete and verified, this sequence of commands stages all modified files (including `package.json` and changelogs), commits them with a standardized message, and pushes these changes to the remote 'main' branch. ```bash git add . git commit -m "chore(release): version bump" git push origin main ``` -------------------------------- ### Publish Updated Packages to npm Locally Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/release-flow.md This command attempts to publish all packages that have new versions to the npm registry directly from the local machine. It is an alternative to relying on the CI workflow for publishing and requires the local environment to be authenticated with npm. ```bash pnpm changeset publish ``` -------------------------------- ### Running Pre-Commit Lint and Test Checks Source: https://github.com/hamidelgendy/arto/blob/main/docs/contributing/local-dev.md Command to ensure code quality and test integrity before committing changes, running lint checks and the full test suite as part of the typical development workflow. ```bash pnpm lint && pnpm test ```