CssChain & ApiChain Utility
css-chain-test (version 1.1.9) is a JavaScript/TypeScript package that serves as a demonstration and test suite for the underlying `CssChain` and `ApiChain` modules. These modules provide a lightweight, chainable API for manipulating collections of DOM elements or plain JavaScript objects. `CssChain` extends native DOM element methods and Array prototypes to allow for fluent, jQuery-like selection and manipulation, enabling operations such as adding event listeners or setting attributes on multiple elements in a single chained call. `ApiChain` offers similar chaining capabilities for arbitrary arrays of JavaScript objects. The package features recent updates focusing on improved TypeScript typings, enhanced shadow DOM support, and unified chain return types. It distinguishes itself by directly extending native browser APIs with a focus on a minimal footprint and modern module support, offering an alternative to heavier DOM manipulation libraries. The release cadence appears active, with frequent minor updates addressing features and typings.
Common errors
-
TypeError: (0, _css_chain_test__WEBPACK_IMPORTED_MODULE_0__.CssChain) is not a function
cause Attempting to call `CssChain` as a constructor (`new CssChain()`) or an incorrect import mechanism (e.g., CommonJS `require` in an ESM context, or vice-versa) prevented the function from being correctly accessed.fixEnsure `CssChain` is imported as a named export for ESM (`import { CssChain } from 'css-chain-test';`) and called directly as a function: `CssChain('selector')`. For CommonJS, use `const { CssChain } = require('css-chain-test');`. -
Cannot read properties of undefined (reading 'value')
cause This error occurs when attempting to access a property (like `.value` or `.textContent`) or an attribute on a `CssChain` or `ApiChain` collection that is empty, meaning no elements matched the selector or the initial array was empty. Getters for empty collections return `undefined`.fixAlways check the `.length` of the collection before attempting to read properties (e.g., `if ($('selector').length > 0) { /* ... */ }`), or implement robust error handling for `undefined` return values. -
Element.matches is not a function
cause This error typically indicates that the `Element.matches()` API, which `CssChain` might rely on (e.g., in `parent(css)`), is not supported in the current execution environment (e.g., an older browser, or a non-browser environment without a polyfill).fixFor older browser targets, include a polyfill for `Element.matches` (e.g., from `core-js` or similar). Ensure the code is running in a modern DOM-compatible environment.
Warnings
- gotcha Reading properties from a `CssChain` collection (e.g., `$('input').value`) only returns the value from the *first* element in the collection. To retrieve values from all matching elements, use `map()` or explicit iteration.
- gotcha When assigning a property to a `CssChain` collection (e.g., `$('input').value = 'new'`), the property is set for *all* elements currently within that collection.
- breaking Prior to version 1.1.9, the return types for some chained methods might have been inconsistent. Applications strictly relying on specific TypeScript return types or chaining assumptions might need minor adjustments after upgrading.
- gotcha Using `on()` (alias for `addEventListener`) or `remove()` (alias for `removeEventListener`) with a `CssChain` collection attaches or detaches the event listener to *each* element in the collection. Ensure proper cleanup to avoid memory leaks if elements or listeners are frequently added/removed.
Install
-
npm install css-chain-test -
yarn add css-chain-test -
pnpm add css-chain-test
Imports
- CssChain
const CssChain = require('css-chain-test');import { CssChain } from 'css-chain-test'; - $ (alias for CssChain)
import $ from 'css-chain-test';
import { CssChain as $ } from 'css-chain-test'; - ApiChain
const ApiChain = require('css-chain-test').ApiChain;import { ApiChain } from 'css-chain-test';
Quickstart
import { CssChain as $, ApiChain } from 'css-chain-test';
// === CssChain: DOM Manipulation ===
// Create some dummy HTML for demonstration
document.body.innerHTML = `
<div id="app">
<button class="my-button" title="Click me">Button 1</button>
<button class="my-button" title="Don't click me">Button 2</button>
<a href="#" class="my-link">Link 1</a>
<input type="text" class="my-input" value="Initial Value">
<div class="container">
<span class="nested-span">Nested Span</span>
</div>
</div>
`;
// Select all buttons and add a click listener, then remove their title
$('button.my-button')
.on('click', (event) => {
const target = event.target as HTMLElement;
console.log(`Button clicked: ${target.textContent} (title was: ${target.title})`);
target.style.backgroundColor = 'lightblue';
})
.attr('data-clicked', 'true') // Set a data attribute
.removeAttribute('title'); // Remove the title attribute after setup
// Select an input and set its value, then retrieve it
const inputField = $('input.my-input');
inputField.value = 'New Value Set By CssChain'; // Set property for all selected inputs
console.log(`Input value (from first element): ${inputField.value}`); // Get property from first element
// Chain multiple event listeners for a link
$('a.my-link')
.on('mouseover', (ev) => (ev.target as HTMLElement).classList.add('hovered'))
.on('mouseleave', (ev) => (ev.target as HTMLElement).classList.remove('hovered'))
.text('Hover and click this link!');
// Query for children within a selected container
$('div#app')
.$('.nested-span') // Alias for querySelectorAll
.text('Updated Nested Span Text')
.css('color', 'green');
// === ApiChain: Object Manipulation ===
const data = [
{ id: 1, name: 'Alice', active: true },
{ id: 2, name: 'Bob', active: false },
{ id: 3, name: 'Charlie', active: true }
];
const chainedData = ApiChain(data);
// Set a property on all objects
chainedData.active = false;
console.log('All data objects made inactive:', chainedData.map(d => d.active));
// Get a property from the first object
const firstId = chainedData.id;
console.log('ID of the first object:', firstId);
// You can still use array methods
const activeUsers = chainedData.filter(user => user.active); // Will be empty now
console.log('Active users after setting all to false:', activeUsers);
// Let's create a new chain and modify it
const moreData = ApiChain([
{ category: 'A', value: 10 },
{ category: 'B', value: 20 },
{ category: 'A', value: 15 }
]);
const sumValues = moreData.reduce((sum, item) => sum + item.value, 0);
console.log('Sum of values in moreData:', sumValues);
// Filter and then set a property
moreData.filter(item => item.category === 'A').status = 'processed';
console.log('More data after processing category A:', moreData);