All notable changes to @wolffm/task will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
BREAKING CHANGE: CSS variable rename --color-*-text → --color-on-*
The --color-primary-text, --color-success-text, --color-warning-text, --color-danger-text, and --color-neutral-text CSS variables have been renamed to --color-on-primary, --color-on-success, --color-on-warning, --color-on-danger, and --color-on-neutral respectively.
Why: The old names were ambiguous — "primary-text" reads as "primary-colored text" rather than "text ON a primary-colored surface." This caused AI agents (and humans) to systematically assign values based on the theme mode (light=black, dark=white) instead of computing from each color's actual luminance. 47% of values were wrong, resulting in invisible button text across many themes.
Migration: Search and replace in custom CSS:
var(--color-primary-text) → var(--color-on-primary)
var(--color-success-text) → var(--color-on-success)
var(--color-warning-text) → var(--color-on-warning)
var(--color-danger-text) → var(--color-on-danger)
var(--color-neutral-text) → var(--color-on-neutral)
- Fixed 57 incorrect
--color-on-*values across all 18 production themes + dev-onlylight-customusing WCAG luminance calculation - Fixed
.pill-btn--activeand.modal-button--primaryusingvar(--color-bg-card)instead of the contrast text variable - Fixed
.task-app__edit-tag-btnhardcodingcolor: whiteinstead of using the contrast variable - Fixed
.task-app__tag-btnusingvar(--color-bg-card)instead ofvar(--color-on-neutral) - Fixed
.card-gradient-offsetbeing permanently broken — was gated behind[data-surface='advanced']which was never set by any code - Fixed global
.var-nameCSS selector in editor bleeding into compact variable grid (scoped to.editor-panel .var-name)
- Light theme: set all
--color-on-*to white for consistent filled button text across all semantic colors - Button hover: replaced inconsistent
filter: brightness()/background: var(--color-*-dark)with unifiedcolor-mix(in oklch, ..., black)across all filled buttons (editor, modal, app) - Editor refactored from 1 monolithic HTML file (2354 lines) into 5 modular files:
editor.html(294 lines),editor.css,editor.js,config.js,color-utils.js - Editor: removed dark sidebar with hardcoded colors, replaced with dropdown theme picker using real theme accent colors
- Editor: removed all 62 hardcoded color values, now uses only
var(--color-*)theme variables - Editor: now imports
bento.cssfromtask-ui-componentsfor metallic surface rendering instead of duplicating styles - Editor: added Simple/Advanced surface mode toggle (Advanced mode incomplete — future work)
- Updated THEME_CREATION_GUIDE.md with critical warning about computing
--color-on-*from luminance, not theme mode - Updated ARCHITECTURE.md, README.md, CONTRIBUTING.md with correct theme counts, file paths, and variable counts
- Added documentation block in style.css header explaining the
--color-on-*convention and semantic color intent - Created
docs/THEME_SYSTEM_RULES.md— research document covering hard rules from Material Design 3, Radix Colors, WCAG 2.2 - Created
claude.md— agent instructions for verification and testing practices
- Removed ~250 lines of commented-out Kitsune Springs A/B/C themes (preserved in THEME_GRAVEYARD.md)
- Removed dead
[data-surface='simple']CSS block from style.css (replaced bydata-simple-modesystem) - Removed dark sidebar from theme editor (62 hardcoded color values eliminated)
Data layer preparation for calendar functionality.
Added optional scheduling fields to the Task interface:
| Field | Type | Description |
|---|---|---|
startTime |
string | null | ISO 8601 scheduled start time |
endTime |
string | null | ISO 8601 scheduled end time or deadline |
Flexible scheduling modes:
- Neither field → Classic board task (existing behavior)
startTimeonly → Open-ended eventendTimeonly → Deadline/due date- Both fields → Fully scheduled time block
Tasks with scheduling fields will appear in both board and calendar views (calendar UI coming in Phase 2).
POST /(Create Task): Now accepts optionalstartTimeandendTimePATCH /:id(Update Task): Now accepts optionalstartTimeandendTime(null to clear)
Deleted redundant/outdated docs:
docs/THEME_EXPORT_GUIDE.md- feature already implemented in @wolffm/themesdocs/TYPES.md- duplicates TypeScript source definitionsdocs/BUILD_REQUIREMENTS.md- merged into CONTRIBUTING.md.husky/HUSKY_SETUP.md- merged into .husky/README.md
Updated remaining docs:
- ARCHITECTURE.md → authoritative strategy document with calendar section
- Fixed theme count: "7 themes" → "12 theme families"
- Trimmed CONTRIBUTING.md, .husky/README.md, themes/THEME_GRAVEYARD.md
Version Bumps:
- @wolffm/task: 3.4.11 → 3.4.12
- @wolffm/themes: 1.1.18 → 1.1.19
Added 4 new semantic color variables across all 18 themes to support badges and status indicators:
New Variables:
| Variable | Purpose |
|---|---|
--color-success-bg |
Background for success badges (10-15% opacity of success color) |
--color-warning |
Warning/intermediate state foreground (typically amber/yellow) |
--color-warning-bg |
Background for warning badges (10-15% opacity of warning color) |
--color-muted-bg |
Background for unknown/neutral badges |
Documentation Updates:
- Updated
README.mdwith new CSS variable documentation - Updated
THEME_CREATION_GUIDE.md:- Color variable count: 27 → 31 colors (33 → 37 total with shadows)
- Added Warning Colors section (2 variables)
- Added
--color-success-bgto Success Colors section - Added
--color-muted-bgto Neutral Colors section - Updated theme checklist
Version Bumps:
- @wolffm/task: 3.3.2 → 3.3.3
- @wolffm/themes: 1.1.2 → 1.1.4 (auto-bumped by version manager)
- @wolffm/task-ui-components: 1.0.6 → 1.0.8 (auto-bumped by version manager)
Added first-class React support with theme metadata and hooks:
New Exports:
-
useTheme()- React hook for stateful theme management- Returns
{ theme, setTheme } - Automatically saves to sessionStorage
- Syncs theme changes across browser tabs via storage events
- Returns
-
THEME_FAMILIES- Pre-configured array of all 9 theme pairs with icons and labels- Each family includes:
lightTheme,darkTheme,lightLabel,darkLabel,lightIcon,darkIcon - Ready to use with
ThemePickerorConnectedThemePickercomponents
- Each family includes:
-
THEME_ICON_MAP- Object mapping theme names to icon components- Maps all 18 themes to their corresponding icons
- Useful for custom theme picker implementations
New Files:
src/metadata.tsx- Theme metadata with icon mappingssrc/useTheme.tsx- React hook implementationscripts/fix-imports.cjs- ESM import fixer (same as task-ui-components)
Package Updates:
- Added peer dependencies: React ^18.0.0 || ^19.0.0, @wolffm/task-ui-components ^1.0.0 (both optional)
- Added JSX support to TypeScript config
- Updated build script to include ESM import fixes
- Enhanced README with React integration examples
Added stateful wrapper component for easier integration:
New Component: ConnectedThemePicker
- Manages
isOpenstate internally - Simpler API - no need to manage picker visibility state
- Same props as
ThemePickerminusisOpenandonToggle - Perfect for quick integration with
@wolffm/themes
Example:
import { ConnectedThemePicker } from '@wolffm/task-ui-components'
import { useTheme, THEME_FAMILIES, THEME_ICON_MAP } from '@wolffm/themes'
function App() {
const { theme, setTheme } = useTheme()
return (
<ConnectedThemePicker
themeFamilies={THEME_FAMILIES}
currentTheme={theme}
onThemeChange={setTheme}
getThemeIcon={theme => {
const Icon = THEME_ICON_MAP[theme]
return Icon ? <Icon /> : null
}}
/>
)
}Documentation:
- Updated README with
ConnectedThemePickerusage examples - Added quick start guide for @wolffm/themes integration
- Reorganized usage examples (Quick Start, ConnectedThemePicker, ThemePicker, Fallback Icons)
Version Bumps:
- @wolffm/task: 3.3.1 → 3.3.2
- @wolffm/themes: 1.1.1 → 1.1.2
- @wolffm/task-ui-components: 1.0.5 → 1.0.6
Purpose: Trigger GitHub Actions deployment workflow and notify parent repository (hadoku_site) of updated packages.
Fixed critical ESM compatibility issue in @wolffm/task-ui-components that blocked integration with strict ESM environments (Astro, Vite):
Problem:
- TypeScript compiler doesn't add
.jsextensions to imports in compiled output - Compiled
dist/index.jshad imports likefrom './components/ThemePicker' - Caused "ERR_MODULE_NOT_FOUND" errors in strict ESM bundlers
Solution:
- Added
"type": "module"to package.json - Changed
moduleResolutionto"bundler"in tsconfig.json - Created post-build script
scripts/fix-imports.cjsthat adds.jsextensions to all relative imports - Updated build script:
tsc && node scripts/fix-imports.cjs && pnpm run copy-css
Result: All compiled imports now have proper .js extensions (e.g., from './components/ThemePicker.js'), ensuring compatibility with Astro and other strict ESM environments.
Package Structure:
task-ui-components/
├── src/
│ ├── components/ThemePicker.tsx # Extracted from main app
│ ├── utils/logger.ts # Production-safe logger
│ └── theme-picker.css # Component styles
├── dist/ # Compiled output
└── package.json # Independent versioning
Exports:
ThemePickercomponent - Standalone theme selection UIloggerutility - Production-safe logging with dev/admin modestheme-picker.css- Component-specific styles
Benefits:
- Reusability - Components can be used across multiple applications
- Independent versioning - Package versions separate from main app
- Better organization - Shared utilities in dedicated package
- Type safety - Full TypeScript support with declaration files
Migrated all console calls to standardized logger:
Files Updated (15 total):
- Core hooks:
useTasks/index.ts(35),useDragAndDrop/index.ts(12),usePreferences.ts(4) - API layer:
client.ts(33),localStorageApi.ts(12),session.ts(8) - Components:
App.tsx(6),BoardsSection.tsx(3),TagContextMenu.tsx(5),BoardButton.tsx(1),BoardContextMenu.tsx(1),CreateTagModal.tsx(1),ErrorBoundary.tsx(1) - Utilities:
preferences.ts(5),auth.ts(2),broadcast.ts(1),helpers.ts(5) - Entry:
entry.tsx(1)
Logger Features:
import { logger } from '@wolffm/task-ui-components'
// Structured logging with context objects
logger.info('[Component] Message', { contextKey: value })
logger.error('[Component] Error', { error: err.message, ...context })
logger.warn('[Component] Warning', { data })
// Production-safe: Only logs in development or for admin users
// No more console.log cluttering productionBefore:
console.log('[App] Loading tasks...', { boardId })
console.error('Failed to save task:', error)After:
logger.info('[App] Loading tasks', { boardId })
logger.error('[App] Failed to save task', {
error: error instanceof Error ? error.message : String(error),
taskId
})Removed:
- ✅ Duplicate logger at
src/utils/logger.ts(old implementation) - ✅ Deprecated
deferredBroadcastwrapper inhelpers.ts - ✅ Unused
withBulkOperationfunction (dead code) - ✅ Unused imports:
SESSION_ID,deferredBroadcastfrom helpers
Result: Cleaner, more maintainable codebase
- @wolffm/task:
3.3.1 - @wolffm/task-ui-components:
1.0.3(new package) - @wolffm/themes:
1.1.0
Developer Experience:
- ✅ All logging now centralized in shared package
- ✅ Consistent logging patterns across entire codebase
- ✅ Production logs only show for admin users
- ✅ Development logs always visible for debugging
Build & Performance:
- ✅ No TypeScript errors
- ✅ All packages building successfully
- ✅ Dev server running without issues
- ✅ No bundle size increase
-
Hooks (4 files)
- useTasks, useDragAndDrop, usePreferences, helpers
-
API Layer (4 files)
- client, localStorageApi, session, auth
-
Components (9 files)
- App, BoardsSection, TagContextMenu, BoardButton, etc.
-
Utilities (3 files)
- preferences, broadcast, entry
- Feature: Husky pre-commit hook now uses smart versioning
- Logic: When patch version reaches
.20, automatically rolls over to next minor version.0 - Example:
3.1.20→3.2.0(instead of3.1.21)
// scripts/version-manager.js
if (patch === 20) {
newVersion = `${major}.${minor + 1}.0` // Roll over
} else {
newVersion = `${major}.${minor}.${patch + 1}` // Regular increment
}- Prevents excessive patch numbers - No more versions like
3.1.47 - Cleaner version progression - Logical minor version increments
- Automated management - No manual intervention needed
- Consistent releases - Every 20 patches becomes a minor release
npm run version:smart- Smart version increment with rollover logicnpm run version:patch- Original patch increment (preserved for manual use)
- Updated:
.husky/pre-commitnow usesversion:smartinstead ofversion:patch - Files modified:
package.json,scripts/version-manager.js,.husky/pre-commit
Old System:
3.0.38 → 3.0.39 → 3.0.40 → 3.0.41 → ... → 3.0.63 → 3.0.64 ...
New System (from this point forward):
3.0.38 → 3.0.39 → 3.0.40 → ... → 3.0.20 → 3.1.0 → 3.1.1 → ... → 3.1.20 → 3.2.0
Note: This change applies to future versions only. Existing version history remains unchanged.
- Issue: Clicking outside the theme picker didn't close it properly
- Root Cause: Drag selection functionality was capturing mouse events before click-outside detection
- User Impact: Theme picker would stay open, requiring manual closing
// NEW: Clean overlay approach like other modals
{showThemePicker && (
<div className="theme-picker__dropdown">
{/* Theme content */}
</div>
)}
{showThemePicker && (
<div
className="theme-picker__overlay" // Full-screen transparent overlay
onClick={onThemePickerToggle} // Closes on any outside click
/>
)}- Removed hacky approach: No more special mouseDown handling in main container
- Removed useClickOutside: No longer needed, direct overlay click handling
- Added overlay CSS: Full-screen transparent overlay for reliable click detection
- Proper positioning: Dropdown positioned relative to button, overlay separate
- Consistent pattern: Same click-outside approach as SettingsModal
- Reliable click-outside: Works regardless of drag selection or other event handlers
- Consistent UX: Same behavior as settings modal and other dropdowns
- Cleaner code: Removed complex event detection logic
- Better performance: Direct click handling instead of document listeners
- Proper separation: Theme picker content and click detection are separate concerns
src/components/AppHeader.tsx- Implemented overlay patternsrc/hooks/useTheme.ts- Removed themePickerRef (no longer needed)src/app/App.tsx- Updated props and removed useClickOutside usagesrc/styles/main.css- Added overlay CSS styling
Removed:
- ❌
useClickOutsidehook usage for theme picker - ❌
themePickerRefparameter and ref handling - ❌ Complex document event listener setup
Added:
- ✅
.theme-picker__overlayCSS class (fixed positioning) - ✅ Overlay click handler for reliable outside click detection
- ✅ Proper event stopPropagation on theme picker content
Build Output:
dist/style.css 43.15 kB │ gzip: 7.08 kB (+0.08 kB)
dist/index.js 108.55 kB │ gzip: 24.71 kB (-0.02 kB)
- Issue: Parent app owns
userIdand can change it, breaking localStorage keys - Issue: Three identifiers (
userType,userId,sessionId) when two suffice - Issue:
userIdprovided no real value oversessionId
Old Architecture (Problematic):
// localStorage keys break when userId changes
'admin-john-doe-main-tasks' // ❌ Breaks if user changes name
'friend-jane-smith-work-tasks' // ❌ Parent can change userId anytime
// API client had redundant parameter
createApi(userType, userId, sessionId) // ❌ userId was redundantNew Architecture (Stable):
// localStorage keys are stable across userId changes
'admin-abc-123-xyz-main-tasks' // ✅ Stable session identifier
'friend-def-456-uvw-work-tasks' // ✅ Parent controls session lifecycle
// API client simplified
createApi(userType, sessionId) // ✅ One identifier, clearer intent// ❌ OLD - userId parameter removed
interface TaskAppProps {
userType?: string
userId?: string
sessionId?: string
}
// ✅ NEW - Only sessionId needed
interface TaskAppProps {
userType?: string
sessionId?: string
}// ❌ OLD
createApi(userType, userId, sessionId)
createLocalStorageApi(userType, userId)
usePreferences(userType, userId, sessionId)
useTasks({ userType, userId, sessionId })
// ✅ NEW
createApi(userType, sessionId)
createLocalStorageApi(userType, sessionId)
usePreferences(userType, sessionId)
useTasks({ userType, sessionId })// ❌ OLD - Keys used userId
'${userType}-${userId}-${boardId}-tasks'
'admin-john-doe-main-tasks'
// ✅ NEW - Keys use sessionId
'${userType}-${sessionId}-${boardId}-tasks'
'admin-abc-123-xyz-main-tasks'Core Storage Layer:
src/api/storage/LocalStorageStorage.ts- Use sessionId in localStorage keyssrc/server/storage.ts- Update Storage interfacesrc/domain/types.ts- Update AuthContext interface
API Layer:
src/api/localStorageApi.ts- Remove userId, use sessionIdsrc/api/client.ts- Remove userId from headers and keys
Domain Layer:
src/domain/handlers/handlers-utils.ts- Use auth.sessionIdsrc/domain/handlers/handlers.ts- Use auth.sessionId
React Components:
src/app/App.tsx- Remove userId parametersrc/app/entry.tsx- Remove userId from TaskAppProps
Hooks:
src/hooks/usePreferences.ts- Use sessionId parametersrc/hooks/useTasks/index.ts- Use sessionId parametersrc/hooks/useTasks/helpers.ts- Use sessionId in broadcasts
Utilities:
src/utils/preferences.ts- Update cleanupOrphanedKeys to use sessionId
- Stable localStorage keys - Keys won't break when parent changes userId
- Simpler architecture - Two identifiers instead of three
- Clearer intent -
userType(behavior) +sessionId(identity) - Parent controls lifecycle - Parent decides when to invalidate session
- Less confusion - One less parameter to pass around
- More robust - No risk of data loss from userId changes
For Parent App:
- ✅ Action Required: Stop passing
userIdprop to task app - ✅ Action Required: Ensure
sessionIdis stable and unique per session ⚠️ Data Impact: Existing localStorage data will not be accessible (uses old keys)
For Users:
⚠️ One-time data loss: Existing tasks/boards will not appear (different localStorage keys)- ✅ Benefit: Data will be stable going forward (no more userId changes breaking keys)
Migration Strategy:
- No automated migration provided - clean slate approach
- Parent app can implement migration if needed by reading old keys and writing to new pattern
dist/style.css 43.07 kB │ gzip: 7.07 kB
dist/index.js 108.26 kB │ gzip: 24.69 kB (+0.05 kB)
- Goal: Clean up codebase by removing unused exports, functions, and type definitions
- Impact: Smaller bundle size, cleaner codebase, easier maintenance
- Method: Comprehensive search for unreferenced code across all TypeScript/JavaScript files
Removed 4 server-infrastructure types that were never used:
// ❌ REMOVED - Never used in codebase
export interface RouterConfig {
dataPath: string
githubConfig?: GitHubConfig
}
export interface GitHubConfig {
owner: string
repo: string
branch: string
token: string
}
export interface SyncQueueItem {
userType: string
dataType: 'tasks' | 'stats'
timestamp: number
}
export type DataType = 'tasks' | 'stats'Analysis:
RouterConfig&GitHubConfig: Leftover from planned server features, never implementedSyncQueueItem: Unused queue system, not referenced anywhereDataType: Unused type alias, no references found
Removed exclusive tag filtering function that was never called:
// ❌ REMOVED - Never called anywhere
export function getTasksByTagExclusive(tasks: Task[], tag: string, topTags: string[]): Task[] {
return tasks.filter(t => {
const taskTags = t.tag?.split(' ') || []
if (!taskTags.includes(tag)) return false
// Only show in the first matching top tag column
const firstMatchingTag = topTags.find(topTag => taskTags.includes(topTag))
return firstMatchingTag === tag
})
}Analysis:
- Created for exclusive tag filtering feature that was later simplified
getTasksByTag()is used instead (6 references)- No imports or calls to this function found
Comprehensive search verified all other code is actively used:
- ✅
findTaskOrThrow- Used 4× in handlers.ts - ✅
findBoardOrThrow- Used 4× in handlers.ts - ✅
updateBoardAtIndex- Used 4× in handlers.ts - ✅
recordStatsEvent- Used 8× in handlers.ts - ✅
extractTasksFromBoard- Used in batchMoveTasks - ✅
prepareTasksForBoard- Used in batchMoveTasks - ✅
updateBatchMoveStats- Used in batchMoveTasks - ✅
closeTask- Used in completeTask & deleteTask - ✅
withTaskOperation- Used 5× in handlers.ts - ✅
withBoardOperation- Used 4× in handlers.ts
- ✅
validateBoardName- Used in App.tsx, CreateBoardModal - ✅
validateAndChangeKey- Used in SettingsModal - ✅
getTaskIdsFromDragEvent- Used 3× in drag/drop components - ✅
getRandomPlaceholder- Used in App.tsx - ✅
formatAge- Used in TaskItem - ✅
getLayoutConfig- Used 2× in TaskLayout - ✅
cleanupOrphanedKeys- Used in usePreferences hook - ✅
migrateFromSessionStorage- Used in usePreferences hook
- ✅
parseTaskInput- Used in useTasks hook - ✅
getTopTags- Used in App.tsx - ✅
getTasksByTag- Used 3× in TaskLayout - ✅
getRemainingTasks- Used in TaskLayout - ✅
getAllTags- Used in App.tsx
- ✅
deferredBroadcast- Used 15× in localStorageApi.ts - ✅
extractBoardTasks- Used 6× in useTasks hook
Files Modified:
src/domain/types.ts- Removed 4 unused type definitions (19 lines)src/domain/utils/tags.ts- Removed 1 unused function (14 lines)
Total Lines Removed: 33 lines of dead code
Bundle Impact:
- Cleaner type exports
- Reduced unused utility code
- No impact on functionality (code was never called)
- ✅ Cleaner codebase - No unused exports cluttering the API surface
- ✅ Easier maintenance - Less code to understand and maintain
- ✅ Better IntelliSense - Fewer unused options in autocomplete
- ✅ Verified active code - Comprehensive search confirms all remaining code is used
- ✅ No regressions - Zero functionality impact (removed code was never executed)
Comprehensive Dead Code Detection:
- ✅ Searched for all export statements across TypeScript files
- ✅ Verified usage of each exported function/interface
- ✅ Checked for imports and references in all files
- ✅ Validated with TypeScript compiler (no new errors)
- ✅ Confirmed all remaining code has active references
Tools Used:
grep_search- Pattern matching across codebaselist_code_usages- Symbol reference checking- TypeScript compiler validation
No change to bundle sizes (removed code was never imported/bundled)
- Issue: Checkboxes in settings modal were black (browser default), making them invisible or hard to see
- Impact: Poor visibility on light themes, inconsistent appearance across themes
- User Report: Screenshot showed black checkboxes on light background in settings modal
Problem:
/* ❌ Before - No color styling, browser default (black) */
.settings-option input[type='checkbox'] {
margin-top: 2px;
cursor: pointer;
width: 18px;
height: 18px;
flex-shrink: 0;
}/* ✅ After - Uses theme's primary color */
.settings-option input[type='checkbox'] {
margin-top: 2px;
cursor: pointer;
width: 18px;
height: 18px;
flex-shrink: 0;
accent-color: var(--color-primary); /* 🎨 Theme-aware color */
appearance: auto;
-webkit-appearance: checkbox;
-moz-appearance: checkbox;
}Checkboxes now match theme primary colors:
| Theme | Primary Color | Checkbox Color | Visibility |
|---|---|---|---|
| Pink Light | #e91e63 | Pink | ✅ Visible |
| Pink Dark | #f48fb1 | Light Pink | ✅ Visible |
| Green Light | #4caf50 | Green | ✅ Visible |
| Green Dark | #81c784 | Light Green | ✅ Visible |
| Blue Light | #2196f3 | Blue | ✅ Visible |
| Blue Dark | #64b5f6 | Light Blue | ✅ Visible |
| Gray Light | #9e9e9e | Gray | ✅ Visible |
| Gray Dark | #bdbdbd | Light Gray | ✅ Visible |
Modern Browsers (accent-color support):
- ✅ Chrome 93+ (September 2021)
- ✅ Firefox 92+ (September 2021)
- ✅ Safari 15.4+ (March 2022)
- ✅ Edge 93+ (September 2021)
Fallback for Older Browsers:
- ✅ Native checkbox appearance preserved
- ✅ Maintains functionality
- ✅ Uses system default colors
- ✅ Consistent theming - Checkboxes match app's color scheme
- ✅ Clear visibility - Works on all light/dark theme variants
- ✅ Native feel - Uses browser's native checkbox appearance
- ✅ Accessible - Maintains all native checkbox functionality
- ✅ No custom styling needed - Leverages modern CSS standard
CSS: 43.15 kB (+0.11 kB) │ gzip: 7.09 kB
For versions prior to 3.0.37, please refer to git commit history.
Package: @wolffm/task
Repository: https://github.com/WolffM/hadoku-task
Registry: https://npm.pkg.github.com