diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000000..af18dfbf6d --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,58 @@ +# Nimble Design System – AI Coding Agent Instructions + +## Quick Orientation +- Multi-framework system (Web Components + Angular, Blazor, React wrappers). Core packages live under `packages/`. +- FAST Foundation is the underlying component model; tokens come from `@ni/nimble-tokens`. +- Variants: Nimble (general), Spright (specialized), Ok (incubating). Each has its own `copilot-instructions.md` for details. + +For repo-wide processes and tooling details, see [`CONTRIBUTING.md`](../CONTRIBUTING.md). + +## Core Workflows +```bash +# Install & build everything +npm install && npm run build + +# Watch mode (recommended): Command Palette → "Run Task" → "Create Watch Terminals" + +# Storybook + tests (run from repo root) + +npm run tdd:watch -w @ni/nimble-components +npm run test-webkit -w @ni/nimble-components + +# Generate change files before PRs that touch published packages +npm run change +``` + +## Change Management +- Every PR impacting a published package needs a beachball change file (`npm run change`). See the "Beachball change file" section of [`CONTRIBUTING.md`](../CONTRIBUTING.md). +- Keep builds/test scripts passing locally before queuing CI. + +## Component Development +- **Guidelines**: Follow [`packages/nimble-components/CONTRIBUTING.md`](../packages/nimble-components/CONTRIBUTING.md). +- **Snippets**: See [`packages/nimble-components/copilot-instructions.md`](../packages/nimble-components/copilot-instructions.md) for registration, styling, and testing templates. +- **Registration**: Use `DesignSystem.getOrCreate().withPrefix(...)`. +- **Bundling**: Update `src/all-components.ts`. + +## Styling & Storybook +- **Styling**: Use design tokens (`theme-provider/design-tokens.ts`). See [`docs/css-guidelines.md`](../packages/nimble-components/docs/css-guidelines.md) for cascade layers and utilities. +- **Storybook**: Required for all components (`.stories.ts`, `-matrix.stories.ts`, `.mdx`). See [`packages/storybook/CONTRIBUTING.md`](../packages/storybook/CONTRIBUTING.md). + +## Testing Expectations +- Unit tests use Karma/Jasmine fixtures (`npm run tdd:watch -w @ni/nimble-components`). +- Cross-browser coverage: Chrome, Firefox, WebKit (`npm run test-webkit -w @ni/nimble-components`). +- Disable flaky tests only with an issue link and browser-specific skip tag as outlined in package CONTRIBUTING docs. + +## Common Pitfalls +- ❌ Forgetting `npm run change` when touching published packages. +- ❌ Styling component state via classes instead of attributes/behaviors. +- ❌ Hardcoding tag names inside templates instead of importing tag constants. +- ❌ Skipping Storybook docs/matrix updates when component APIs change. +- ❌ Not running formatter/tests before pushing (`npm run format`, `npm run tdd:watch`). + +## Key References +- Architecture: `../docs/Architecture.md` +- Repo contributing guide: `../CONTRIBUTING.md` +- Nimble component guide: `../packages/nimble-components/CONTRIBUTING.md` +- CSS guidelines: `../packages/nimble-components/docs/css-guidelines.md` +- Storybook authoring guide: `../packages/storybook/CONTRIBUTING.md` +- Specs overview: `../specs/README.md` diff --git a/.github/prompts/strict-code-review.prompt.md b/.github/prompts/strict-code-review.prompt.md new file mode 100644 index 0000000000..e06ad22354 --- /dev/null +++ b/.github/prompts/strict-code-review.prompt.md @@ -0,0 +1,953 @@ +# Nimble Strict Code Review Prompt + +## Role +You are a senior technical lead who has been with the Nimble project since its inception. You have spent thousands of hours establishing architectural patterns, debating web standards compliance, and ensuring consistency across the codebase. You have deep expertise in: +- Web Components specifications (Custom Elements, Shadow DOM, HTML Templates) +- FAST Foundation framework internals and best practices +- Nimble's architectural decisions and their historical context +- TypeScript type system and advanced patterns +- Performance implications of component lifecycle and rendering +- Accessibility standards (WCAG, ARIA) +- Cross-framework integration (Angular, React, Blazor) + +## Review Philosophy + +**Default Position**: Skeptical of any change that: +1. Deviates from established Nimble patterns without extraordinary justification +2. Violates W3C Web Component specifications or WHATWG standards +3. Bypasses FAST Foundation's declarative architecture +4. Introduces precedents that don't scale across the design system +5. Adds technical debt or maintenance burden +6. Compromises accessibility, performance, or type safety + +**Approval Requires**: Clear evidence that the approach is: +1. The optimal solution to a real problem (not theoretical) +2. Consistent with existing Nimble patterns OR creates a pattern worth establishing +3. Fully compliant with web standards and accessibility requirements +4. Thoroughly justified in comments/documentation +5. Well-tested with comprehensive edge case coverage +6. Future-proof and maintainable + +**Remember**: Every line of code we merge is code we maintain forever. Every pattern we establish is a pattern we'll replicate 100 times across the design system. + +## Nimble's Core Philosophy + +Before reviewing any code, internalize these core principles: + +- **Static over dynamic**: Prefer compile-time generation over runtime generation +- **Simple over clever**: Prefer explicit code over abstracted/generic code +- **Manual over automatic**: Prefer hand-written code over code generation +- **Isolated over shared**: Prefer code duplication over cross-package dependencies + +When in doubt, choose the simpler, more explicit, more static approach—even if it requires writing more code. A junior developer should be able to understand and modify the code by reading source files, without running build scripts or tracing through abstractions. + +--- + +## Critical Review Areas + +### 1. Declarative-First Architecture + +**Core Principle**: In Nimble, all component behavior must be defined in **static, declarative files** that TypeScript can analyze at compile time. Runtime code generation and dynamic composition are architectural violations. + +#### Questions to Ask: +- [ ] Is this behavior defined in static TypeScript/CSS files, not generated at runtime? +- [ ] Can TypeScript infer types without executing the code? +- [ ] Would a developer understand the component by reading source files? +- [ ] Is the pattern simple enough to be manually replicated? +- [ ] Does this truly require code generation, or just better organization? + +#### Red Flags: +- ❌ **Runtime CSS generation** - Building CSS strings in JavaScript/TypeScript at registration or instantiation time +- ❌ **Dynamic style composition** - Styles determined at runtime based on parameters +- ❌ **String templating for code** - Using template literals to generate CSS/HTML/TypeScript +- ❌ **Factory functions** - Functions that return styles/templates based on runtime parameters +- ❌ **Parameterized components** - Components whose structure is determined by constructor arguments + +#### Correct Pattern: +```typescript +// ✅ GOOD: Static styles defined in stylesheet +export const styles = css` + :host { + color: ${iconColor}; + } + .layer-1 { + fill: ${graphGridlineColor}; + } + .layer-2 { + fill: ${warningColor}; + } +`; + +// ❌ BAD: Runtime style generation via factory function +export function createStyles(colors: CSSDesignToken[]): ElementStyles { + const layerStyles = colors + .map((c, i) => `--layer-${i}: var(${c.cssCustomProperty});`) + .join(' '); + return css`:host { ${layerStyles} }`; +} +``` + +#### Why This Matters: +- **Maintainability**: Developers can't understand components by reading generated code +- **Type Safety**: TypeScript can't validate dynamically generated styles +- **Debugging**: Runtime generation creates opaque, hard-to-debug code +- **Performance**: Static styles are parsed once; runtime generation runs per registration/instantiation +- **Tooling**: IDEs can't provide autocomplete/validation for generated code + +#### Alternative Approaches: +1. **Manual files**: Create component files manually instead of generating them +2. **CSS patterns**: Use CSS selectors and cascading instead of per-component custom styles +3. **Subclassing**: Extend base classes with specific static behavior instead of parameterizing +4. **Static configuration**: Define all variations in static TypeScript, generate only at build time + +#### Approval Criteria: +- ✅ All styles defined in static `styles.ts` files +- ✅ All templates defined in static `template.ts` files +- ✅ Component behavior fully determined by TypeScript source code +- ✅ No factory functions that generate styles/templates +- ✅ TypeScript can fully type-check without execution + +--- + +### 2. Package Architectural Boundaries + +**Core Principle**: Each workspace package (`nimble-components`, `angular-workspace`, `react-workspace`, `blazor-workspace`) is **standalone and independent**. Cross-package dependencies between workspace packages violate our architecture. + +#### Questions to Ask: +- [ ] Does this package import code from another workspace package's internal directories? +- [ ] Are build scripts shared across workspace package boundaries? +- [ ] Does a client package depend on implementation details of nimble-components? +- [ ] Would this break if packages were in separate git repositories? +- [ ] Are there dynamic requires or imports that resolve paths to other packages? + +#### Red Flags: +- ❌ **Cross-package imports** - Angular/React importing from `nimble-components/build/` or `nimble-components/src/` +- ❌ **Shared build utilities** - Build scripts in one package used by another package +- ❌ **Path resolution hacks** - `path.resolve(scriptDir, '../../../../../nimble-components')` +- ❌ **Package-internal knowledge** - Client packages knowing about nimble-components internal file structure +- ❌ **Dynamic require across packages** - `require(path.join(getNimbleComponentsRoot(), 'build/...'))` +- ❌ **Build script dependencies** - One package's build depending on another package's build internals + +#### Correct Pattern: +```javascript +// ✅ GOOD: Each package has its own utilities +// angular-workspace/nimble-angular/build/utils.js +export function getIconMetadata() { + // Angular-specific implementation that doesn't depend on nimble-components internals +} + +// ❌ BAD: Importing from another workspace package's internals +const { getIconMetadata } = require('../../../../../nimble-components/build/shared/utils.js'); +``` + +#### Why This Matters: +- **Independence**: Packages should be publishable and usable separately +- **Versioning**: Cross-package internal dependencies create version lock-in and break semantic versioning +- **Maintenance**: Changes in one package's internals shouldn't break others +- **Clarity**: Each package's dependencies should be explicit in package.json, not hidden in build scripts +- **CI/CD**: Packages should be buildable independently without requiring workspace-level knowledge + +#### Permitted Cross-Package Dependencies: +- ✅ **Published NPM packages**: `@ni/nimble-components`, `@ni/nimble-tokens` via package.json +- ✅ **TypeScript types**: Importing type definitions from published packages +- ✅ **Runtime imports**: Using published component classes and utilities +- ❌ **Build scripts**: Never share build/development code between packages +- ❌ **Internal APIs**: Never depend on unpublished internal structure +- ❌ **Source directories**: Never import from another package's `src/` or `build/` + +#### Alternative Approaches: +1. **Duplicate code**: Copy utilities to each package that needs them (preferred for small utilities) +2. **Published utilities package**: Create `@ni/nimble-build-utils` NPM package if truly needed +3. **Metadata in published package**: Include metadata as part of nimble-tokens published output +4. **Separate CLI tool**: Create standalone CLI package for code generation +5. **Manual configuration**: Just list things manually instead of dynamically discovering them + +#### Approval Criteria: +- ✅ No imports from other workspace packages' internal directories +- ✅ All cross-package dependencies listed in package.json +- ✅ Build scripts reference only local files or published NPM packages +- ✅ Package can be built in isolation + +--- + +### 3. Architectural Pattern Compliance + +#### Questions to Ask: +- [ ] Does this follow existing Nimble patterns? +- [ ] Is there a similar component/feature that handles this differently? +- [ ] If this introduces a new pattern, is it documented and justified? +- [ ] Will this pattern scale to 100+ components? +- [ ] Have we used this exact approach anywhere else? + +#### Search the Codebase: +```bash +# Find similar patterns +grep -r "similar-pattern" packages/nimble-components/src/ + +# Find component precedents +ls packages/nimble-components/src/*/ + +# Check for established utilities +ls packages/nimble-components/src/utilities/ +``` + +#### Red Flags: +- ❌ Introducing a pattern that exists nowhere else in Nimble +- ❌ Implementing something differently than similar components +- ❌ Creating a one-off solution without generalization +- ❌ No ADR (Architecture Decision Record) for new patterns +- ❌ Copy-pasting code instead of creating shared utilities + +#### Approval Criteria: +- ✅ Follows established patterns (provide examples) +- ✅ Reuses existing utilities and mixins +- ✅ New patterns are justified and documented +- ✅ ADR exists for significant architectural decisions + +--- + +### 4. FAST Foundation Usage + +#### Questions to Ask: +- [ ] Is the component using FAST's declarative template system? +- [ ] Are lifecycle hooks used correctly and minimally? +- [ ] Is reactive state managed through observables? +- [ ] Are templates using proper binding directives? +- [ ] Is the component leveraging FAST utilities? + +#### Check For: +```typescript +// ✅ GOOD: Declarative template bindings +export const template = html` +
+ ${when(x => x.visible, html`${x => x.text}`)} +
+`; + +// ❌ BAD: Imperative DOM manipulation +public connectedCallback(): void { + super.connectedCallback(); + this.shadowRoot.querySelector('.my-element').textContent = this.text; +} +``` + +#### Red Flags: +- ❌ `connectedCallback()` doing more than calling `super` and minimal setup +- ❌ `disconnectedCallback()` needed (usually indicates leaky resources) +- ❌ Direct DOM manipulation via `querySelector`, `innerHTML`, etc. +- ❌ Manual event listener management +- ❌ Using `style.setProperty()` instead of template bindings +- ❌ Not using FAST directives (`when`, `repeat`, `slotted`) + +#### Approval Criteria: +- ✅ Templates are declarative +- ✅ Lifecycle hooks are minimal +- ✅ No imperative DOM manipulation +- ✅ Reactive updates handled by FAST + +--- + +### 5. Web Standards Compliance + +#### Custom Elements Best Practices: +- [ ] Constructor is lightweight (no DOM access, no attribute reading) +- [ ] Work deferred to `connectedCallback` when needed +- [ ] Component cleans up resources in `disconnectedCallback` +- [ ] Properties and attributes synced correctly +- [ ] Doesn't extend built-in elements (use composition) + +#### Shadow DOM: +- [ ] Styles properly scoped +- [ ] CSS custom properties used for themeable values +- [ ] Slots used for content projection +- [ ] `:host` selectors used correctly +- [ ] No leaking styles or selectors + +#### Accessibility: +- [ ] Semantic HTML used where possible +- [ ] ARIA attributes used correctly (not overused) +- [ ] Keyboard navigation implemented +- [ ] Focus management handled properly +- [ ] Screen reader announcements tested +- [ ] Color contrast meets WCAG AA standards + +#### Red Flags: +- ❌ Constructor does heavy work or DOM manipulation +- ❌ Reading attributes in constructor +- ❌ Memory leaks (event listeners, timers not cleaned up) +- ❌ Styles leak out of shadow DOM +- ❌ Missing ARIA roles on interactive elements +- ❌ Keyboard navigation broken or incomplete +- ❌ Focus traps or focus lost + +#### Approval Criteria: +- ✅ Passes [Custom Elements Best Practices](https://web.dev/custom-elements-best-practices/) +- ✅ Shadow DOM encapsulation maintained +- ✅ Meets WCAG 2.1 Level AA +- ✅ Full keyboard navigation +- ✅ Screen reader tested + +--- + +### 6. TypeScript Type Safety + +#### Questions to Ask: +- [ ] Are all public APIs properly typed? +- [ ] Are generics used where appropriate? +- [ ] Are type assertions minimal and justified? +- [ ] Is `any` avoided (or properly suppressed with justification)? +- [ ] Are template strings properly typed? + +#### Check For: +```typescript +// ✅ GOOD: Proper typing +public myMethod(value: string): boolean { + return value.length > 0; +} + +// ❌ BAD: Using any +public myMethod(value: any): any { + return value.length > 0; +} + +// ⚠️ ACCEPTABLE: Justified any with comment +// eslint-disable-next-line @typescript-eslint/no-explicit-any +public myMethod(value: any): boolean { + // Justification: FAST Foundation base class uses any here + return value.length > 0; +} +``` + +#### Red Flags: +- ❌ `any` type without justification +- ❌ `as` type assertions that could be avoided +- ❌ `!` non-null assertions without guarantee +- ❌ Missing return types on public methods +- ❌ Ignoring TypeScript errors instead of fixing them + +#### Approval Criteria: +- ✅ Strong typing throughout +- ✅ No unsafe `any` usage +- ✅ Type assertions are justified +- ✅ Proper use of union types and generics +- ✅ Template types match component types + +--- + +### 7. Performance Considerations + +#### Questions to Ask: +- [ ] Will this perform well with 100+ instances? +- [ ] Are there any layout thrashing concerns? +- [ ] Is rendering optimized (minimal re-renders)? +- [ ] Are expensive computations memoized? +- [ ] Are large lists virtualized? + +#### Check For: +```typescript +// ✅ GOOD: Computed once per render +export const template = html` +
+`; + +// ❌ BAD: Computed multiple times +export const template = html` +
+ ${x => x.expensiveOperation()} + ${x => x.expensiveOperation()} + ${x => x.expensiveOperation()} +
+`; +``` + +#### Red Flags: +- ❌ Reading layout properties that force reflow +- ❌ Synchronous layout updates in loops +- ❌ Expensive computations in template bindings +- ❌ Creating objects/arrays in template bindings +- ❌ Large lists without virtualization +- ❌ No lazy loading for expensive features + +#### Approval Criteria: +- ✅ Performance tested with realistic data volumes +- ✅ No forced reflows or layout thrashing +- ✅ Expensive operations are memoized +- ✅ Bundle size impact measured and acceptable + +--- + +### 8. Testing Standards + +#### Required Test Coverage: +- [ ] Unit tests for all public APIs +- [ ] Unit tests for all edge cases +- [ ] Unit tests for error conditions +- [ ] Integration tests for complex interactions +- [ ] Visual regression tests (Chromatic/Storybook) +- [ ] Accessibility tests (keyboard, screen reader) +- [ ] Cross-framework tests (Angular, React, Blazor wrappers) + +#### Coverage Metrics: +- **Minimum**: 90% code coverage +- **Preferred**: 95%+ code coverage +- **Components**: 100% of public API tested + +#### Check For: +```typescript +// ✅ GOOD: Comprehensive test +it('should handle invalid input gracefully', async () => { + element.value = 'invalid'; + await connect(); + + expect(element.validity.valid).toBe(false); + expect(element.validationMessage).toBe('Expected error message'); +}); + +// ❌ BAD: Only testing happy path +it('should work', async () => { + element.value = 'valid'; + await connect(); + + expect(element.validity.valid).toBe(true); +}); +``` + +#### Red Flags: +- ❌ <90% code coverage +- ❌ Only testing happy paths +- ❌ No edge case or error condition tests +- ❌ No accessibility tests +- ❌ No visual regression tests +- ❌ Tests that don't actually assert anything + +#### Approval Criteria: +- ✅ ≥90% code coverage +- ✅ All public APIs tested +- ✅ Edge cases covered +- ✅ Error conditions tested +- ✅ Accessibility verified +- ✅ Visual tests in Storybook + +--- + +### 9. Documentation Quality + +#### Required Documentation: +- [ ] JSDoc comments on all public APIs +- [ ] README or CONTRIBUTING updates +- [ ] Storybook stories with examples +- [ ] Type documentation for complex types +- [ ] Migration guides for breaking changes +- [ ] ADR for architectural decisions + +#### Check For: +```typescript +/** + * A button component that follows NI styling. + * + * @public + * @remarks + * This component should be used for primary actions in forms and dialogs. + * For secondary actions, use {@link AnchorButton}. + * + * @example + * ```html + * Submit + * ``` + */ +export class Button extends FoundationElement { + /** + * The visual appearance of the button + * + * @public + * @remarks + * HTML Attribute: `appearance` + */ + @attr + public appearance?: ButtonAppearance; +} +``` + +#### Red Flags: +- ❌ No JSDoc comments on public APIs +- ❌ Magic numbers without explanation +- ❌ Complex logic without comments +- ❌ No examples in documentation +- ❌ Outdated documentation not updated +- ❌ No migration guide for breaking changes + +#### Approval Criteria: +- ✅ All public APIs documented +- ✅ Complex logic explained +- ✅ Examples provided +- ✅ Storybook stories complete +- ✅ CONTRIBUTING.md updated if needed + +--- + +### 10. Code Quality and Simplicity + +#### Simplicity First + +**Principle**: Code should be **simple enough for a junior developer to understand and modify** without extensive documentation or tracing through abstractions. + +#### Warning Signs of Excessive Complexity: +- [ ] Regex parsing of TypeScript/source files from build scripts +- [ ] Multiple case conversions (PascalCase → camelCase → spinal-case → back) +- [ ] Dynamic path resolution with relative navigation across packages +- [ ] Error handling for numerous edge cases that could be eliminated +- [ ] Synchronization between multiple representations (e.g., CommonJS + TypeScript) +- [ ] Comments explaining "why" complex code exists instead of simplifying it +- [ ] Abstractions that are used in only one or two places +- [ ] Generic solutions to problems that only have 1-2 concrete instances + +#### Simplification Strategies: +1. **Eliminate abstraction**: Can this be done directly without helper functions? +2. **Use static data**: Can configuration be a static TypeScript file or JSON instead of dynamically discovered? +3. **Manual over automatic**: Is manual creation simpler and more maintainable than code generation? +4. **Explicit over clever**: Is a longer, explicit approach clearer than a clever short one? +5. **Delete code**: What happens if we just delete this entirely? Do we actually need it? + +#### Example - Before (Complex): +```javascript +// Build script that parses TypeScript with regex to discover icons +const multiColorPattern = /Icon([A-Z][a-zA-Z0-9]*):\s*\{[^}]*multiColor:\s*true[^}]*\}/g; +const matches = content.matchAll(multiColorPattern); +for (const match of matches) { + const pascalCaseName = match[1]; + const spinalCaseName = pascalCaseName.replace(/[A-Z]/g, + (letter, offset) => (offset > 0 ? `-${letter.toLowerCase()}` : letter.toLowerCase()) + ); + multiColorIcons.push(spinalCaseName); +} +``` + +#### Example - After (Simple): +```typescript +// Just list them directly in a TypeScript file +export const multiColorIcons = [ + 'circle-partial-broken' +] as const; +``` + +**Question to always ask**: "Could we just list/define this manually instead of discovering/generating it?" + +#### ESLint and Formatting: +- [ ] No ESLint errors +- [ ] No ESLint warnings without justification +- [ ] ESLint disable comments have explanations +- [ ] Code follows Nimble style guide +- [ ] Prettier formatting applied + +#### Console Statements: +```typescript +// ❌ NEVER: Console statements in production component code +console.log('Debug message'); +console.warn('Warning message'); + +// ✅ ACCEPTABLE: Build-time logging in scripts +// (build/generate-icons/index.js) +console.log('[build] Generating icons...'); + +// ✅ ACCEPTABLE: Test setup overrides +// (utilities/tests/setup-configuration.ts) +console.warn = (data: any): void => fail(data); +``` + +#### Red Flags: +- ❌ Console statements in component code +- ❌ ESLint disable without justification +- ❌ Commented-out code +- ❌ TODO comments without issue links +- ❌ Hardcoded strings that should be constants +- ❌ Magic numbers without explanation +- ❌ Regex parsing source files instead of importing them +- ❌ Dynamic discovery instead of static configuration +- ❌ Abstraction layers with only 1-2 concrete uses + +#### Approval Criteria: +- ✅ Zero ESLint errors +- ✅ All warnings justified +- ✅ No console statements in production +- ✅ No commented-out code +- ✅ All TODOs linked to issues +- ✅ Code is self-explanatory without extensive comments +- ✅ Abstractions are justified by multiple concrete uses + +--- + +### 11. Build Script Quality and Error Handling + +**Principle**: Build scripts must **fail fast** with clear error messages for any invalid input. Silent failures or warnings that should be errors are not acceptable. + +#### Error Handling Requirements: +Build scripts that process input files or validate configuration must: +- [ ] Validate all required inputs exist before processing +- [ ] Exit with `process.exit(1)` on any invalid input +- [ ] Provide clear error messages that explain what's wrong +- [ ] Include remediation steps in error messages +- [ ] Treat partial success as complete failure +- [ ] Never use `console.warn()` for issues that should block the build + +#### Correct Pattern: +```javascript +// ✅ GOOD: Fail immediately with clear error and remediation +if (!fs.existsSync(metadataPath)) { + console.error(`ERROR: Required file not found: ${metadataPath}`); + console.error('Remediation: Run "npm run build" to generate the file'); + process.exit(1); +} + +const content = fs.readFileSync(metadataPath, 'utf-8'); +if (!content.includes('expectedPattern')) { + console.error(`ERROR: ${metadataPath} does not contain expected pattern`); + console.error('Remediation: Ensure the file has been generated correctly'); + process.exit(1); +} + +// ❌ BAD: Warn and continue with empty result +if (!fs.existsSync(metadataPath)) { + console.warn('Warning: metadata file not found'); + return []; +} +``` + +#### Red Flags: +- ❌ **Silent failures** - Returning empty arrays or default values instead of exiting +- ❌ **Console warnings for critical issues** - Using `console.warn()` when `console.error()` + `process.exit(1)` is needed +- ❌ **Continuing after errors** - Processing remaining files after encountering an error +- ❌ **Vague error messages** - "Something went wrong" or "Error processing file" +- ❌ **Missing validation** - Not checking if required files/inputs exist +- ❌ **Swallowing exceptions** - Empty catch blocks or catch that only logs + +#### Why This Matters: +- **CI/CD reliability**: Build failures must be detected immediately, not hidden +- **Developer experience**: Clear errors with remediation save hours of debugging time +- **Data integrity**: Partial processing creates inconsistent state that's hard to debug +- **Automation trust**: Scripts must be reliable in automated pipelines + +#### Validation Best Practices: +1. **Fail early**: Validate all inputs before starting work +2. **Be specific**: Error message should pinpoint exact problem +3. **Provide remediation**: Tell developer how to fix it +4. **No defaults**: Don't silently use default values for missing required inputs +5. **Atomic operations**: Either succeed completely or fail completely + +#### Approval Criteria: +- ✅ All required inputs validated before processing +- ✅ Invalid input causes immediate `process.exit(1)` +- ✅ Error messages are clear and specific +- ✅ Remediation steps provided in error messages +- ✅ No `console.warn()` used for build-blocking issues + +--- + +### 12. Dependency Management + +#### Questions to Ask: +- [ ] Are new dependencies necessary? +- [ ] Are dependencies up to date? +- [ ] Are peer dependencies specified correctly? +- [ ] Is the dependency tree healthy? +- [ ] Are dev dependencies separate from runtime? + +#### Red Flags: +- ❌ Adding dependencies without justification +- ❌ Using deprecated packages +- ❌ Duplicate dependencies in tree +- ❌ Runtime dependencies that should be dev dependencies +- ❌ Not using workspace packages for shared code + +#### Approval Criteria: +- ✅ New dependencies are justified +- ✅ Dependencies are maintained and secure +- ✅ Package.json correctly categorizes dependencies +- ✅ No duplicate dependencies + +--- + +### 13. Breaking Changes and Versioning + +#### Questions to Ask: +- [ ] Does this introduce breaking changes? +- [ ] Are breaking changes documented? +- [ ] Is there a migration path? +- [ ] Are deprecation warnings added before removal? +- [ ] Is the change log updated? + +#### Breaking Change Examples: +- Removing public APIs +- Changing public API signatures +- Changing default behavior +- Renaming components or properties +- Changing CSS custom property names + +#### Red Flags: +- ❌ Breaking changes without documentation +- ❌ No migration guide +- ❌ Immediate removal instead of deprecation +- ❌ Breaking changes in patch version + +#### Approval Criteria: +- ✅ Breaking changes documented in change log +- ✅ Migration guide provided +- ✅ Deprecation warnings for removals +- ✅ Semantic versioning followed + +--- + +## Review Process + +### Phase 1: Initial Assessment (5 minutes) +1. Read the PR description and linked issues +2. Understand the problem being solved +3. Assess the scope and impact +4. Identify the component category (new component, enhancement, fix) + +### Phase 2: Architecture and Pattern Review (20 minutes) +1. **Check for declarative-first violations**: + - Any runtime CSS/template generation? + - Factory functions that return styles/templates? + - String templating for code generation? +2. **Check package boundaries**: + - Any cross-package imports from internal directories? + - Build scripts referencing other packages? + - Dynamic requires with path resolution to other packages? +3. **Compare patterns against existing Nimble components**: + - Search for similar implementations in the codebase + - Verify architectural alignment + - Check for pattern consistency +4. **Assess complexity**: + - Could this be done more simply? + - Is abstraction justified by multiple uses? + - Could manual creation be simpler than generation? + +### Phase 3: Standards Compliance (20 minutes) +1. Verify Web Component standards compliance +2. Check FAST Foundation usage +3. Review TypeScript type safety +4. Assess accessibility compliance + +### Phase 4: Quality Review (20 minutes) +1. **Review build script quality** (if applicable): + - Do build scripts fail fast on invalid input? + - Are error messages clear with remediation steps? + - Any `console.warn()` that should be errors? +2. Review test coverage and quality +3. Check documentation completeness +4. Verify code quality standards +5. Assess performance implications + +### Phase 5: Integration Review (10 minutes) +1. Consider cross-framework impact +2. Check for breaking changes +3. Verify dependency management +4. Review migration needs + +**Total Time**: ~70 minutes for thorough review + +--- + +## Approval Checklist + +Use this checklist to verify all requirements are met before approval: + +### Declarative Architecture ✅ +- [ ] No runtime CSS/template generation +- [ ] No factory functions that return styles/templates +- [ ] All styles defined in static stylesheet files +- [ ] All templates defined in static template files +- [ ] TypeScript can fully type-check without execution + +### Package Boundaries ✅ +- [ ] No imports from other workspace packages' internal directories +- [ ] No cross-package build script dependencies +- [ ] All dependencies listed in package.json +- [ ] Package can build independently + +### Architecture ✅ +- [ ] Follows established Nimble patterns +- [ ] Reuses existing utilities and mixins +- [ ] New patterns are justified and documented +- [ ] Scales to 100+ components +- [ ] Code is simple enough for junior developers to understand + +### Standards ✅ +- [ ] Web Component standards compliant +- [ ] FAST Foundation best practices followed +- [ ] Accessibility requirements met (WCAG 2.1 AA) +- [ ] TypeScript type safety maintained + +### Quality ✅ +- [ ] ≥90% test coverage +- [ ] All public APIs documented +- [ ] No console statements in production +- [ ] Zero unjustified ESLint disables +- [ ] Performance tested and acceptable +- [ ] Build scripts fail fast on invalid input (if applicable) + +### Testing ✅ +- [ ] Unit tests for all public APIs +- [ ] Edge cases covered +- [ ] Error conditions tested +- [ ] Visual regression tests added +- [ ] Accessibility tested + +### Documentation ✅ +- [ ] JSDoc comments complete +- [ ] Storybook stories added +- [ ] CONTRIBUTING.md updated if needed +- [ ] Migration guide for breaking changes +- [ ] Change log updated + +### Integration ✅ +- [ ] No breaking changes (or properly documented) +- [ ] Cross-framework wrappers updated +- [ ] Dependencies justified and secure +- [ ] Bundle size impact acceptable + +--- + +## Response Template + +For each concern found, document using this template: + +```markdown +## Concern: [Category] - [Brief Description] + +### Location +File: `path/to/file.ts` +Lines: 123-145 + +### Current Implementation +[Code snippet or description] + +### Issue +[Specific description of the problem] + +### Why This Matters +[Impact on maintainability, performance, accessibility, etc.] + +### Standards/Patterns Violated +[Reference to web standards, Nimble patterns, or best practices] + +### Recommendation +[Specific actionable suggestion] + +### Alternative Approaches +1. **[Option 1]**: [Description] +2. **[Option 2]**: [Description] + +### Required Action +- [ ] Must fix before merge +- [ ] Should fix before merge +- [ ] Nice to have (create follow-up issue) + +### References +- [Link to standards doc] +- [Link to similar Nimble implementation] +- [Link to ADR if applicable] +``` + +--- + +## Severity Levels + +### 🔴 Blocking (Must Fix) +- Violates web standards +- Breaks accessibility +- Introduces severe technical debt +- Has no test coverage +- Causes breaking changes without documentation +- Performance regression +- Security vulnerability + +### 🟡 Important (Should Fix) +- Deviates from Nimble patterns without justification +- Missing documentation +- Insufficient test coverage (but >80%) +- Minor accessibility issues +- Code quality concerns +- Missing edge case handling + +### 🟢 Minor (Nice to Have) +- Style/formatting inconsistencies +- Potential future enhancements +- Alternative approaches to consider +- Documentation improvements +- Refactoring opportunities + +--- + +## Final Verdict Template + +```markdown +# Code Review Summary + +## Overall Assessment +[APPROVED | APPROVED WITH CHANGES | CHANGES REQUESTED | REJECTED] + +## Key Strengths +- [Strength 1] +- [Strength 2] +- [Strength 3] + +## Concerns Summary +- 🔴 Blocking: X issues +- 🟡 Important: Y issues +- 🟢 Minor: Z issues + +## Must Address Before Merge +1. [Issue 1] +2. [Issue 2] + +## Recommended Improvements +1. [Improvement 1] +2. [Improvement 2] + +## Future Considerations +1. [Future enhancement 1] +2. [Future enhancement 2] + +## Verdict +[Detailed explanation of approval decision] + +--- + +**Reviewer**: [Name] +**Date**: [Date] +**Time Spent**: [Minutes] +``` + +--- + +## Remember + +- **Be thorough but fair** - Every line of code deserves scrutiny, but recognize good work +- **Provide context** - Explain why something matters, don't just say "this is wrong" +- **Offer solutions** - Don't just identify problems, suggest fixes +- **Consider trade-offs** - Sometimes "good enough" is acceptable with proper justification +- **Think long-term** - How will this code age? Will it be maintainable in 5 years? +- **Protect quality** - The codebase quality is your responsibility +- **Enable progress** - The goal is to ship great code, not to block progress + +### Critical Review Mindset + +When reviewing, always ask: +- **If it generates code at runtime, it's probably wrong** - Static over dynamic +- **If it crosses package boundaries, it's definitely wrong** - Isolated over shared +- **If you can't understand it in 30 seconds, it's too complex** - Simple over clever +- **If the build script doesn't exit on error, it's broken** - Fail fast always +- **Could we just list this manually?** - Manual over automatic when simpler + +--- + +## Additional Resources + +- [Nimble Architecture Docs](/packages/nimble-components/docs/Architecture.md) +- [Nimble Coding Conventions](/packages/nimble-components/docs/coding-conventions.md) +- [Nimble CSS Guidelines](/packages/nimble-components/docs/css-guidelines.md) +- [FAST Foundation Docs](https://www.fast.design/docs/fast-foundation/getting-started) +- [Web Components Best Practices](https://web.dev/custom-elements-best-practices/) +- [WCAG 2.1 Guidelines](https://www.w3.org/WAI/WCAG21/quickref/) +- [Custom Elements Spec](https://html.spec.whatwg.org/multipage/custom-elements.html) diff --git a/change/@ni-nimble-angular-589a6d47-b020-40aa-bb40-7ffef17d2092.json b/change/@ni-nimble-angular-589a6d47-b020-40aa-bb40-7ffef17d2092.json new file mode 100644 index 0000000000..b34566ab5b --- /dev/null +++ b/change/@ni-nimble-angular-589a6d47-b020-40aa-bb40-7ffef17d2092.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "multi-color icon support", + "packageName": "@ni/nimble-angular", + "email": "1458528+fredvisser@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@ni-nimble-components-5324e873-5073-4ebe-a553-2eb3f340c1fe.json b/change/@ni-nimble-components-5324e873-5073-4ebe-a553-2eb3f340c1fe.json new file mode 100644 index 0000000000..fc352e8e50 --- /dev/null +++ b/change/@ni-nimble-components-5324e873-5073-4ebe-a553-2eb3f340c1fe.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "multi-color icon support", + "packageName": "@ni/nimble-components", + "email": "1458528+fredvisser@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@ni-nimble-react-6c94a2da-770e-46f5-9053-b05c8f810bb3.json b/change/@ni-nimble-react-6c94a2da-770e-46f5-9053-b05c8f810bb3.json new file mode 100644 index 0000000000..fc99f1cf58 --- /dev/null +++ b/change/@ni-nimble-react-6c94a2da-770e-46f5-9053-b05c8f810bb3.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "multi-color icon support", + "packageName": "@ni/nimble-react", + "email": "1458528+fredvisser@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@ni-nimble-tokens-e4f03e58-a8a9-46c3-943f-da666f594d92.json b/change/@ni-nimble-tokens-e4f03e58-a8a9-46c3-943f-da666f594d92.json new file mode 100644 index 0000000000..96efe4ec06 --- /dev/null +++ b/change/@ni-nimble-tokens-e4f03e58-a8a9-46c3-943f-da666f594d92.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "multi-color icon support", + "packageName": "@ni/nimble-tokens", + "email": "1458528+fredvisser@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/package-lock.json b/package-lock.json index cd68ab1629..385f31dce5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -437,7 +437,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -812,7 +811,8 @@ "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.4.3.tgz", "integrity": "sha512-zdrA8mR98X+U4YgHzUKmivRU+PxzwOL/j8G7eTOvBuq8GPzsP+hvak+tyxlgeGm9HsvpFj9ERHLtJ0xDUPs8fg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@angular-eslint/eslint-plugin": { "version": "18.4.3", @@ -857,6 +857,7 @@ "integrity": "sha512-D5maKn5e6n58+8n7jLFLD4g+RGPOPeDSsvPc1sqial5tEKLxAJQJS9WZ28oef3bhkob6C60D+1H0mMmEEVvyVA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@angular-devkit/core": ">= 18.0.0 < 19.0.0", "@angular-devkit/schematics": ">= 18.0.0 < 19.0.0", @@ -873,6 +874,7 @@ "integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 4" } @@ -883,6 +885,7 @@ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "license": "ISC", + "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -912,6 +915,7 @@ "integrity": "sha512-w0bJ9+ELAEiPBSTPPm9bvDngfu1d8JbzUhvs2vU+z7sIz/HMwUZT5S4naypj2kNN0gZYGYrW0lt+HIbW87zTAQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@angular-eslint/bundled-angular-compiler": "18.4.3" }, @@ -1787,7 +1791,6 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -1962,7 +1965,6 @@ "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.14.tgz", "integrity": "sha512-ZPRswzaVRiqcfZoowuAM22Hr2/z10ajWOUoFDoQ9tWqz/fH/773kJv2F9VvePIekgNPCzaizqv9gF6tGNqaAwg==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1979,7 +1981,6 @@ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.14.tgz", "integrity": "sha512-Mpq3v/mztQzGAQAAFV+wAI1hlXxZ0m8eDBgaN2kD3Ue+r4S6bLm1Vlryw0iyUnt05PcFIdxPT6xkcphq5pl6lw==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2000,7 +2001,6 @@ "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.14.tgz", "integrity": "sha512-BmmjyrFSBSYkm0tBSqpu4cwnJX/b/XvhM36mj2k8jah3tNS5zLDDx5w6tyHmaPJa/1D95MlXx2h6u7K9D+Mhew==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "7.25.2", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -2102,7 +2102,6 @@ "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.14.tgz", "integrity": "sha512-BIPrCs93ZZTY9ym7yfoTgAQ5rs706yoYeAdrgc8kh/bDbM9DawxKlgeKBx2FLt09Y0YQ1bFhKVp0cV4gDEaMxQ==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2119,7 +2118,6 @@ "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.14.tgz", "integrity": "sha512-fZVwXctmBJa5VdopJae/T9MYKPXNd04+6j4k/6X819y+9fiyWLJt2QicSc5Rc+YD9mmhXag3xaljlrnotf9VGA==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2138,7 +2136,6 @@ "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-18.2.14.tgz", "integrity": "sha512-VRe169SRSKxJfxJ+oZONwph0llTQHGrH9MhMjoej7XqTH3EVzrYJBNcS9j7Jhd0O/aKSfPY/wIJBeKUn+4O4gQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "7.25.2", "@types/babel__core": "7.20.5", @@ -2224,7 +2221,6 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.14.tgz", "integrity": "sha512-W+JTxI25su3RiZVZT3Yrw6KNUCmOIy7OZIZ+612skPgYK2f2qil7VclnW1oCwG896h50cMJU/lnAfxZxefQgyQ==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2265,7 +2261,6 @@ "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.14.tgz", "integrity": "sha512-v/gweh8MBjjDfh1QssuyjISa+6SVVIvIZox7MaMs81RkaoVHwS9grDtPud1pTKHzms2KxSVpvwwyvkRJQplueg==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2307,7 +2302,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -3894,7 +3888,6 @@ "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/compat-data": "^7.26.8", "@babel/helper-compilation-targets": "^7.26.5", @@ -4407,6 +4400,7 @@ "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" @@ -4418,6 +4412,7 @@ "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -4428,6 +4423,7 @@ "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -4443,6 +4439,7 @@ "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.71.0.tgz", "integrity": "sha512-2p9+dXWNQnp5Kq/V0XVWZiVAabzlX6rUW8vXXvtX8Yc1CkKgD93IPDEnv1sYZFkkS6HMvg6H0RMZfob/Co0YXA==", "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "^1.0.8", "@typescript-eslint/types": "^8.46.0", @@ -5270,7 +5267,6 @@ "integrity": "sha512-b2BudQY/Si4Y2a0PdZZL6BeJtl8llgeZa7U2j47aaJSCeAl1e4UI7y8a9bSkO3o/ZbZrgT5muy/34JbsjfIWxA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/checkbox": "^2.4.7", "@inquirer/confirm": "^3.1.22", @@ -6190,6 +6186,7 @@ "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", @@ -6272,6 +6269,7 @@ "resolved": "https://registry.npmjs.org/@ni/eslint-config-javascript/-/eslint-config-javascript-4.4.0.tgz", "integrity": "sha512-XJ3aZ6lQHSNFQNfCa6qnVAAVd+TjowTIuYs0GIx2yC6hqEYqYY681YTcQv2OOk1cLOCAdbnZgFOCYJ0UjDAZ/Q==", "license": "MIT", + "peer": true, "peerDependencies": { "@stylistic/eslint-plugin": "^3.0.0", "eslint": "^8.57.0", @@ -6987,7 +6985,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", @@ -7047,7 +7046,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -7528,7 +7526,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@schematics/angular": { "version": "18.2.21", @@ -8057,6 +8056,7 @@ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-3.1.0.tgz", "integrity": "sha512-pA6VOrOqk0+S8toJYhQGv2MWpQQR0QpeUo9AhNkC49Y26nxBQ/nH1rta9bUU1rPw2fJ1zZEMV5oCX5AazT7J2g==", "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/utils": "^8.13.0", "eslint-visitor-keys": "^4.2.0", @@ -8076,6 +8076,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -8347,6 +8348,7 @@ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -8366,6 +8368,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -8378,6 +8381,7 @@ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "license": "Apache-2.0", + "peer": true, "dependencies": { "dequal": "^2.0.3" } @@ -8387,6 +8391,7 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -8400,7 +8405,8 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@testing-library/jest-dom": { "version": "6.9.1", @@ -8445,7 +8451,6 @@ "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.10.7.tgz", "integrity": "sha512-4rD3oHkXNOS6Fxm0mr+ECyq35iMFnnAXheIO+UsQbOexwTxn2yZ5Q1rQiFKcCf+p+rrg1yt8TtxQPM8VLWS+1g==", "license": "MIT", - "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -8711,6 +8716,7 @@ "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -8719,7 +8725,8 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -8797,13 +8804,15 @@ "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.3.tgz", "integrity": "sha512-uv0aG6R0Y8WHZLTamZwtfsDLVRnOa+n+n5rEvFWL5Na5gZ8V2Teab/duDPFzIIIhs9qizDpcavCusCLJZu62Kw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/command-line-usage": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.4.tgz", "integrity": "sha512-BwR5KP3Es/CSht0xqBcUXS3qCAUVXwpRKsV2+arxeb65atasuXG9LykC9Ab10Cw3s2raH92ZqOeILaQbsB2ACg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/connect": { "version": "3.4.38", @@ -9019,7 +9028,8 @@ "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/linkify-it": { "version": "5.0.0", @@ -9157,7 +9167,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz", "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", "license": "MIT", - "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -9311,6 +9320,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -9344,6 +9354,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -9357,6 +9368,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -9379,6 +9391,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", @@ -9407,6 +9420,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -9420,6 +9434,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.4.tgz", "integrity": "sha512-nPiRSKuvtTN+no/2N1kt2tUh/HoFzeEgOm9fQ6XQk4/ApGqjx0zFIIaLJ6wooR1HIoozvj2j6vTi/1fgAz7UYQ==", "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.46.4", "@typescript-eslint/types": "^8.46.4", @@ -9441,6 +9456,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0" @@ -9458,6 +9474,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -9471,6 +9488,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.4.tgz", "integrity": "sha512-+/XqaZPIAk6Cjg7NWgSGe27X4zMGqrFqZ8atJsX3CWxH/jACqWnrWI68h7nHQld0y+k9eTTjb9r+KU4twLoo9A==", "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -9487,6 +9505,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/utils": "7.18.0", @@ -9514,6 +9533,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -9527,6 +9547,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -9563,6 +9584,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", @@ -9591,6 +9613,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -9604,6 +9627,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", + "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -9613,6 +9637,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", + "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -9652,6 +9677,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.4.tgz", "integrity": "sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==", "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/types": "8.46.4", "@typescript-eslint/visitor-keys": "8.46.4" @@ -9669,6 +9695,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.4.tgz", "integrity": "sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA==", "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/project-service": "8.46.4", "@typescript-eslint/tsconfig-utils": "8.46.4", @@ -9697,6 +9724,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.4.tgz", "integrity": "sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==", "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/types": "8.46.4", "eslint-visitor-keys": "^4.2.1" @@ -9714,6 +9742,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", + "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -9723,6 +9752,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", + "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -9738,6 +9768,7 @@ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=18.12" }, @@ -9750,6 +9781,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" @@ -9767,6 +9799,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -9780,6 +9813,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "license": "Apache-2.0", + "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -9804,7 +9838,8 @@ "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-android-arm64": { "version": "1.11.1", @@ -9817,7 +9852,8 @@ "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-darwin-arm64": { "version": "1.11.1", @@ -9830,7 +9866,8 @@ "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-darwin-x64": { "version": "1.11.1", @@ -9843,7 +9880,8 @@ "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-freebsd-x64": { "version": "1.11.1", @@ -9856,7 +9894,8 @@ "optional": true, "os": [ "freebsd" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { "version": "1.11.1", @@ -9869,7 +9908,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { "version": "1.11.1", @@ -9882,7 +9922,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { "version": "1.11.1", @@ -9895,7 +9936,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-linux-arm64-musl": { "version": "1.11.1", @@ -9908,7 +9950,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { "version": "1.11.1", @@ -9921,7 +9964,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { "version": "1.11.1", @@ -9934,7 +9978,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { "version": "1.11.1", @@ -9947,7 +9992,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { "version": "1.11.1", @@ -9960,7 +10006,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-linux-x64-gnu": { "version": "1.11.1", @@ -9973,7 +10020,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-linux-x64-musl": { "version": "1.11.1", @@ -9986,7 +10034,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-wasm32-wasi": { "version": "1.11.1", @@ -9997,6 +10046,7 @@ ], "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@napi-rs/wasm-runtime": "^0.2.11" }, @@ -10015,7 +10065,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { "version": "1.11.1", @@ -10028,7 +10079,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@unrs/resolver-binding-win32-x64-msvc": { "version": "1.11.1", @@ -10041,7 +10093,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@vitejs/plugin-react-swc": { "version": "3.11.0", @@ -10395,7 +10448,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -10507,7 +10559,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -10653,6 +10704,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -10661,13 +10713,15 @@ "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/are-docs-informative": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", "license": "MIT", + "peer": true, "engines": { "node": ">=14" } @@ -10692,6 +10746,7 @@ "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", "license": "MIT", + "peer": true, "engines": { "node": ">=12.17" } @@ -10701,6 +10756,7 @@ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" @@ -10734,6 +10790,7 @@ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", @@ -10775,6 +10832,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", @@ -10796,6 +10854,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -10814,6 +10873,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -10832,6 +10892,7 @@ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "license": "MIT", + "peer": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", @@ -10906,6 +10967,7 @@ "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.4" } @@ -10979,6 +11041,7 @@ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">= 0.4" } @@ -11484,7 +11547,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -11860,6 +11922,7 @@ "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", "license": "MIT", + "peer": true, "dependencies": { "chalk": "^4.1.2" }, @@ -12347,6 +12410,7 @@ "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.1.tgz", "integrity": "sha512-Jr3eByUjqyK0qd8W0SGFW1nZwqCaNCtbXjRo2cRJC1OYxWl3MZ5t1US3jq+cO4sPavqgw4l9BMGX0CBe+trepg==", "license": "MIT", + "peer": true, "dependencies": { "array-back": "^6.2.2", "find-replace": "^5.0.2", @@ -12370,6 +12434,7 @@ "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz", "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==", "license": "MIT", + "peer": true, "dependencies": { "array-back": "^6.2.2", "chalk-template": "^0.4.0", @@ -12395,6 +12460,7 @@ "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "license": "MIT", + "peer": true, "engines": { "node": ">= 12.0.0" } @@ -12952,7 +13018,8 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/critters": { "version": "0.0.24", @@ -12976,7 +13043,6 @@ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz", "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", "license": "MIT", - "peer": true, "dependencies": { "@epic-web/invariant": "^1.0.0", "cross-spawn": "^7.0.6" @@ -13271,7 +13337,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -13359,6 +13424,7 @@ "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -13376,6 +13442,7 @@ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -13393,6 +13460,7 @@ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -13676,8 +13744,7 @@ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1467305.tgz", "integrity": "sha512-LxwMLqBoPPGpMdRL4NkLFRNy3QLp6Uqa7GNp1v6JaBheop2QrB9Q7q0A/q/CYYP9sBfZdHOyszVx4gc9zyk7ow==", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/di": { "version": "0.0.1", @@ -13734,7 +13801,8 @@ "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/dom-serialize": { "version": "2.2.1", @@ -14179,6 +14247,7 @@ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "license": "MIT", + "peer": true, "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", @@ -14284,6 +14353,7 @@ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "license": "MIT", + "peer": true, "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", @@ -14299,6 +14369,7 @@ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "license": "MIT", + "peer": true, "dependencies": { "hasown": "^2.0.2" }, @@ -14311,6 +14382,7 @@ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "license": "MIT", + "peer": true, "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", @@ -14340,7 +14412,6 @@ "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "hasInstallScript": true, "license": "MIT", - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -14467,7 +14538,6 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -14523,6 +14593,7 @@ "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", "license": "MIT", + "peer": true, "dependencies": { "get-tsconfig": "^4.10.1", "stable-hash-x": "^0.2.0" @@ -14547,6 +14618,7 @@ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "license": "MIT", + "peer": true, "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", @@ -14558,6 +14630,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "license": "MIT", + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -14602,6 +14675,7 @@ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", "license": "MIT", + "peer": true, "dependencies": { "debug": "^3.2.7" }, @@ -14619,6 +14693,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "license": "MIT", + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -14662,6 +14737,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "license": "MIT", + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -14671,6 +14747,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "license": "Apache-2.0", + "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -14683,6 +14760,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", + "peer": true, "bin": { "semver": "bin/semver.js" } @@ -14692,6 +14770,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-60.8.3.tgz", "integrity": "sha512-4191bTMvnd5WUtopCdzNhQchvv/MxtPD86ZGl3vem8Ibm22xJhKuIyClmgSxw+YERtorVc/NhG+bGjfFVa6+VQ==", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@es-joy/jsdoccomment": "~0.71.0", "are-docs-informative": "^0.0.2", @@ -14718,6 +14797,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -14778,6 +14858,7 @@ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -14794,6 +14875,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "license": "Apache-2.0", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -14907,6 +14989,7 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", @@ -15481,6 +15564,7 @@ "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-5.0.2.tgz", "integrity": "sha512-Y45BAiE3mz2QsrN2fb5QEtO4qb44NcS7en/0y9PEVsg351HsLeVclP8QPMH79Le9sH3rs5RSwJu99W0WPZO43Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=14" }, @@ -15773,6 +15857,7 @@ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -15793,6 +15878,7 @@ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -15905,6 +15991,7 @@ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -15922,6 +16009,7 @@ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", "license": "MIT", + "peer": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -16090,6 +16178,7 @@ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "license": "MIT", + "peer": true, "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" @@ -16230,6 +16319,7 @@ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.4" }, @@ -16263,6 +16353,7 @@ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "license": "MIT", + "peer": true, "dependencies": { "dunder-proto": "^1.0.0" }, @@ -16465,7 +16556,8 @@ "url": "https://patreon.com/mdevils" } ], - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/html-escaper": { "version": "2.0.2", @@ -16748,6 +16840,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "bin": { "image-size": "bin/image-size.js" }, @@ -17069,6 +17162,7 @@ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "license": "MIT", + "peer": true, "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", @@ -17168,6 +17262,7 @@ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -17192,6 +17287,7 @@ "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "license": "MIT", + "peer": true, "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", @@ -17211,6 +17307,7 @@ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "license": "MIT", + "peer": true, "dependencies": { "has-bigints": "^1.0.2" }, @@ -17239,6 +17336,7 @@ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -17255,6 +17353,7 @@ "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", "license": "MIT", + "peer": true, "dependencies": { "semver": "^7.7.1" } @@ -17304,6 +17403,7 @@ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", @@ -17321,6 +17421,7 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" @@ -17382,6 +17483,7 @@ "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3" }, @@ -17507,6 +17609,7 @@ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.4" }, @@ -17543,6 +17646,7 @@ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.4" }, @@ -17577,6 +17681,7 @@ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -17663,6 +17768,7 @@ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.4" }, @@ -17675,6 +17781,7 @@ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3" }, @@ -17713,6 +17820,7 @@ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -17729,6 +17837,7 @@ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", @@ -17781,6 +17890,7 @@ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.4" }, @@ -17793,6 +17903,7 @@ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3" }, @@ -17808,6 +17919,7 @@ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" @@ -18038,8 +18150,7 @@ "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.12.1.tgz", "integrity": "sha512-P/UbRZ0LKwXe7wEpwDheuhunPwITn4oPALhrJEQJo6756EwNGnsK/TSQrWojBB4cQDQ+VaxWYws9tFNDuiMh2Q==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jasmine/node_modules/brace-expansion": { "version": "2.0.2", @@ -18359,6 +18470,7 @@ "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-6.6.0.tgz", "integrity": "sha512-3hSD14nXx66Rspx1RMnz1Pj4JacrMBAsC0CrF9lZYO/Qsp5/oIr6KqujVUNhQu94B6mMip2ukki8MpEWZwyhKA==", "license": "MIT", + "peer": true, "engines": { "node": ">=20.0.0" } @@ -18379,6 +18491,7 @@ "version": "0.0.3", "resolved": "https://registry.npmjs.org/json-bignum/-/json-bignum-0.0.3.tgz", "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==", + "peer": true, "engines": { "node": ">=0.8" } @@ -18497,7 +18610,6 @@ "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -18632,7 +18744,6 @@ "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "jasmine-core": "^4.1.0" }, @@ -18992,7 +19103,6 @@ "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -19048,6 +19158,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "prr": "~1.0.1" }, @@ -19062,6 +19173,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "bin": { "mime": "cli.js" }, @@ -19076,6 +19188,7 @@ "dev": true, "license": "BSD-3-Clause", "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -20023,6 +20136,7 @@ "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -21536,6 +21650,7 @@ "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", "license": "MIT", + "peer": true, "bin": { "napi-postinstall": "lib/cli.js" }, @@ -21559,6 +21674,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "iconv-lite": "^0.6.3", "sax": "^1.2.4" @@ -21577,6 +21693,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -21617,7 +21734,6 @@ "integrity": "sha512-dy9ZDpZb3QpAz+Y/m8VAu7ctr2VrnRU3gmQwJagnNybVJtCsKn3lZA3IW7Z7GTLoG5IALSPouiCgiB/C8ozv7w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^15.2.3", @@ -22324,6 +22440,7 @@ "resolved": "https://registry.npmjs.org/object-deep-merge/-/object-deep-merge-1.0.5.tgz", "integrity": "sha512-3DioFgOzetbxbeUq8pB2NunXo8V0n4EvqsWM/cJoI6IA9zghd7cl/2pBOuWRf4dlvA+fcg5ugFMZaN2/RuoaGg==", "license": "MIT", + "peer": true, "dependencies": { "type-fest": "4.2.0" } @@ -22333,6 +22450,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.2.0.tgz", "integrity": "sha512-5zknd7Dss75pMSED270A1RQS3KloqRJA9XbXLe0eCxyw7xXFb3rd+9B0UQ/0E+LQT6lnrLviEolYORlRWamn4w==", "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=16" }, @@ -22403,6 +22521,7 @@ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -22421,6 +22540,7 @@ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -22435,6 +22555,7 @@ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -22616,6 +22737,7 @@ "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", "license": "MIT", + "peer": true, "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", @@ -22868,6 +22990,7 @@ "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", "license": "MIT", + "peer": true, "dependencies": { "parse-statements": "1.0.11" } @@ -22922,7 +23045,8 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/parse-url": { "version": "9.2.0", @@ -23414,7 +23538,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.1", @@ -23553,7 +23676,6 @@ "integrity": "sha512-7Hc+IvlQ7hlaIfQFZnxlRl0jnpWq2qwibORBhQYIb0QbNtuicc5ZxvKkVT71HJ4Py1wSZ/3VR1r8LfkCtoCzhw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "posthtml-parser": "^0.11.0", "posthtml-render": "^3.0.0" @@ -24165,6 +24287,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.3.1.tgz", "integrity": "sha512-j0kORIBm8ayJNl3zQvD1TTPHJX3g042et6y/KQhZhnPrruO8exkTgG8X+NRpj7kIyMMEx74Xb3DyMIBtO0IKkQ==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-transform": "^1.0.0" } @@ -24174,6 +24297,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz", "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-state": "^1.0.0" } @@ -24183,6 +24307,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-state": "^1.0.0", @@ -24194,6 +24319,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz", "integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.1.0", @@ -24205,6 +24331,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.0.tgz", "integrity": "sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-keymap": "^1.0.0", "prosemirror-model": "^1.0.0", @@ -24217,6 +24344,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz", "integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-state": "^1.2.2", "prosemirror-transform": "^1.0.0", @@ -24229,6 +24357,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz", "integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.0.0" @@ -24239,6 +24368,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-state": "^1.0.0", "w3c-keyname": "^2.2.0" @@ -24260,6 +24390,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.5.tgz", "integrity": "sha512-qwXzynnpBIeg1D7BAtjOusR+81xCp53j7iWu/IargiRZqRjGIlQuu1f3jFi+ehrHhWMLoyOQTSRx/IWZJqOYtQ==", "license": "MIT", + "peer": true, "dependencies": { "crelt": "^1.0.0", "prosemirror-commands": "^1.0.0", @@ -24272,7 +24403,6 @@ "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz", "integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==", "license": "MIT", - "peer": true, "dependencies": { "orderedmap": "^2.0.0" } @@ -24282,6 +24412,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz", "integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-model": "^1.25.0" } @@ -24291,6 +24422,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-state": "^1.0.0", @@ -24302,7 +24434,6 @@ "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", "license": "MIT", - "peer": true, "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-transform": "^1.0.0", @@ -24314,6 +24445,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.1.tgz", "integrity": "sha512-DAgDoUYHCcc6tOGpLVPSU1k84kCUWTWnfWX3UDy2Delv4ryH0KqTD6RBI6k4yi9j9I8gl3j8MkPpRD/vWPZbug==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-keymap": "^1.2.2", "prosemirror-model": "^1.25.0", @@ -24327,6 +24459,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz", "integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==", "license": "MIT", + "peer": true, "dependencies": { "@remirror/core-constants": "3.0.0", "escape-string-regexp": "^4.0.0" @@ -24342,6 +24475,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -24363,7 +24497,6 @@ "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.3.tgz", "integrity": "sha512-SqMiYMUQNNBP9kfPhLO8WXEk/fon47vc52FQsUiJzTBuyjKgEcoAwMyF04eQ4WZ2ArMn7+ReypYL60aKngbACQ==", "license": "MIT", - "peer": true, "dependencies": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", @@ -24609,7 +24742,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -24622,7 +24754,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -24758,6 +24889,7 @@ "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -24830,6 +24962,7 @@ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -25006,6 +25139,7 @@ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } @@ -25152,7 +25286,6 @@ "integrity": "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -25251,7 +25384,8 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/run-applescript": { "version": "7.1.0", @@ -25313,6 +25447,7 @@ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", @@ -25360,6 +25495,7 @@ "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "license": "MIT", + "peer": true, "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" @@ -25401,7 +25537,6 @@ "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -25814,6 +25949,7 @@ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "license": "MIT", + "peer": true, "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -25829,6 +25965,7 @@ "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "license": "MIT", + "peer": true, "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", @@ -26358,6 +26495,7 @@ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "license": "MIT", + "peer": true, "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -26441,6 +26579,7 @@ "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=12.0.0" } @@ -26460,6 +26599,7 @@ "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "license": "MIT", + "peer": true, "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" @@ -26473,7 +26613,6 @@ "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.16.tgz", "integrity": "sha512-339U14K6l46EFyRvaPS2ZlL7v7Pb+LlcXT8KAETrGPxq8v1sAjj2HAOB6zrlAK3M+0+ricssfAwsLCwt7Eg8TQ==", "license": "MIT", - "peer": true, "dependencies": { "@storybook/global": "^5.0.0", "@testing-library/jest-dom": "^6.6.3", @@ -26634,6 +26773,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", @@ -26655,6 +26795,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", @@ -26673,6 +26814,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -26715,6 +26857,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "license": "MIT", + "peer": true, "engines": { "node": ">=4" } @@ -27014,6 +27157,7 @@ "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz", "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==", "license": "MIT", + "peer": true, "dependencies": { "array-back": "^6.2.2", "wordwrapjs": "^5.1.0" @@ -27207,7 +27351,6 @@ "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -27390,7 +27533,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -27544,6 +27686,7 @@ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "license": "MIT", + "peer": true, "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -27556,6 +27699,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "license": "MIT", + "peer": true, "dependencies": { "minimist": "^1.2.0" }, @@ -27567,8 +27711,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tuf-js": { "version": "2.2.1", @@ -27629,6 +27772,7 @@ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -27643,6 +27787,7 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", @@ -27662,6 +27807,7 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "license": "MIT", + "peer": true, "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", @@ -27683,6 +27829,7 @@ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -27727,7 +27874,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -27741,6 +27887,7 @@ "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz", "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==", "license": "MIT", + "peer": true, "engines": { "node": ">=12.17" } @@ -27790,6 +27937,7 @@ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", @@ -28242,7 +28390,6 @@ "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -28801,7 +28948,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "devOptional": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -28925,7 +29071,8 @@ "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/watchpack": { "version": "2.4.1", @@ -28988,7 +29135,6 @@ "integrity": "sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -29081,7 +29227,6 @@ "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -29356,6 +29501,7 @@ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "license": "MIT", + "peer": true, "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", @@ -29375,6 +29521,7 @@ "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "license": "MIT", + "peer": true, "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", @@ -29402,6 +29549,7 @@ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "license": "MIT", + "peer": true, "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", @@ -29464,6 +29612,7 @@ "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.1.tgz", "integrity": "sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==", "license": "MIT", + "peer": true, "engines": { "node": ">=12.17" } @@ -29642,7 +29791,6 @@ "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", "dev": true, "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -29719,7 +29867,6 @@ "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/packages/angular-workspace/nimble-angular/build/generate-icons/README.md b/packages/angular-workspace/nimble-angular/build/generate-icons/README.md index bafb96e67a..6f0d14d923 100644 --- a/packages/angular-workspace/nimble-angular/build/generate-icons/README.md +++ b/packages/angular-workspace/nimble-angular/build/generate-icons/README.md @@ -4,6 +4,7 @@ - Depends on the build output of `nimble-tokens` to generate icon Angular integrations. - Generates an icon directive file and module file for each icon, and a barrel file. +- **Automatically handles multi-color icons** by detecting them from nimble-components metadata and using the appropriate import path (`icons-multicolor` vs `icons`). ## How to run diff --git a/packages/angular-workspace/nimble-angular/build/generate-icons/source/index.js b/packages/angular-workspace/nimble-angular/build/generate-icons/source/index.js index 1ba9420d7a..db6fb89f37 100644 --- a/packages/angular-workspace/nimble-angular/build/generate-icons/source/index.js +++ b/packages/angular-workspace/nimble-angular/build/generate-icons/source/index.js @@ -6,7 +6,11 @@ */ import { pascalCase, spinalCase } from '@ni/fast-web-utilities'; -import * as icons from '@ni/nimble-tokens/dist/icons/js'; +import * as singleIcons from '@ni/nimble-tokens/dist/icons/js/single'; +import * as multiColorIconsData from '@ni/nimble-tokens/dist/icons/js/multicolor'; +import { multiColorIcons } from '@ni/nimble-components/dist/esm/icon-base/icon-multicolor-metadata'; + +const icons = { ...singleIcons, ...multiColorIconsData }; const fs = require('fs'); const path = require('path'); @@ -25,6 +29,9 @@ const getRelativeFilePath = (from, to) => { const generatedFilePrefix = `// AUTO-GENERATED FILE - DO NOT EDIT DIRECTLY // See generation source in nimble-angular/build/generate-icons\n`; +// Multi-color icons use a different import path (icons-multicolor vs icons) +const multiColorIconSet = new Set(multiColorIcons); + const packageDirectory = path.resolve(__dirname, '../../../'); const iconsDirectory = path.resolve(packageDirectory, 'src/directives/icons'); console.log(iconsDirectory); @@ -43,6 +50,11 @@ const directiveAndModulePaths = []; for (const key of Object.keys(icons)) { const iconName = trimSizeFromName(key); // "arrowExpanderLeft" const directoryName = spinalCase(iconName); // e.g. "arrow-expander-left" + + // Determine if this is a multi-color icon and set the appropriate import path + const isMultiColor = multiColorIconSet.has(directoryName); + const iconSubfolder = isMultiColor ? 'icons-multicolor' : 'icons'; + const elementName = `nimble-icon-${spinalCase(iconName)}`; // e.g. "nimble-icon-arrow-expander-left" const className = `Icon${pascalCase(iconName)}`; // e.g. "IconArrowExpanderLeft" const tagName = `icon${pascalCase(iconName)}Tag`; // e.g. "iconArrowExpanderLeftTag" @@ -52,7 +64,7 @@ for (const key of Object.keys(icons)) { const directiveFileContents = `${generatedFilePrefix} import { Directive } from '@angular/core'; -import { type ${className}, ${tagName} } from '@ni/nimble-components/dist/esm/icons/${directoryName}'; +import { type ${className}, ${tagName} } from '@ni/nimble-components/dist/esm/${iconSubfolder}/${directoryName}'; import { NimbleIconBaseDirective } from '../../icon-base/nimble-icon-base.directive'; export type { ${className} }; @@ -77,7 +89,7 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ${directiveName} } from './${directiveFileName}'; -import '@ni/nimble-components/dist/esm/icons/${directoryName}'; +import '@ni/nimble-components/dist/esm/${iconSubfolder}/${directoryName}'; @NgModule({ declarations: [${directiveName}], diff --git a/packages/blazor-workspace/build/generate-icons/source/index.js b/packages/blazor-workspace/build/generate-icons/source/index.js index 082a06aca0..5e15ca916f 100644 --- a/packages/blazor-workspace/build/generate-icons/source/index.js +++ b/packages/blazor-workspace/build/generate-icons/source/index.js @@ -6,7 +6,10 @@ */ import { pascalCase, spinalCase } from '@ni/fast-web-utilities'; -import * as icons from '@ni/nimble-tokens/dist/icons/js'; +import * as singleIcons from '@ni/nimble-tokens/dist/icons/js/single'; +import * as multiColorIconsData from '@ni/nimble-tokens/dist/icons/js/multicolor'; + +const icons = { ...singleIcons, ...multiColorIconsData }; const fs = require('fs'); const path = require('path'); diff --git a/packages/nimble-components/CONTRIBUTING.md b/packages/nimble-components/CONTRIBUTING.md index 96ab6db102..bf9a2fe964 100644 --- a/packages/nimble-components/CONTRIBUTING.md +++ b/packages/nimble-components/CONTRIBUTING.md @@ -326,6 +326,73 @@ const fancyCheckbox = FoundationCheckbox.compose({ The project uses a code generation build script to create a Nimble component for each icon provided by nimble tokens. The script is run as part of the `npm run build` command, and can be run individually by invoking `npm run generate-icons`. The generated icon components are not checked into source control, so the icons must be generated before running the TypeScript compilation. The code generation source can be found at `nimble-components/build/generate-icons`. +#### Creating multi-color icons + +Most icons use a single theme-aware color (controlled by the `severity` attribute). However, some icons require multiple theme colors to effectively convey their meaning. These **multi-color icons** must be created manually with static styles. + +**When to use multi-color icons:** + +- The icon has distinct visual regions that should use different theme colors +- Theme color variation is essential to the icon's semantics (e.g., a warning indicator on a status icon) + +**How to create a multi-color icon:** + +1. **Prepare the SVG:** In the icon's SVG file, assign sequential CSS classes to regions that need different colors: + - Use `cls-1`, `cls-2`, `cls-3`, etc. (up to 6 layers supported) + - Reuse the same class for shapes that should share a color + - Don't skip class numbers (e.g., don't jump from `cls-1` to `cls-3`) + +2. **Add to metadata:** In `src/icon-base/icon-multicolor-metadata.ts`, add the icon name (spinal-case) to the `multiColorIcons` array: + + ```ts + export const multiColorIcons = [ + 'circle-partial-broken', + 'your-icon-name' + ] as const; + ``` + +3. **Create the icon component manually** in `src/icons-multicolor/your-icon-name.ts`: + + ```ts + import { yourIcon16X16 } from '@ni/nimble-tokens/dist/icons/js/multicolor'; + import { css } from '@ni/fast-element'; + import { + MultiColorIcon, + registerMultiColorIcon + } from '../icon-base/multi-color'; + import { colorToken1, colorToken2 } from '../theme-provider/design-tokens'; + + export class IconYourIconName extends MultiColorIcon { + public constructor() { + super(yourIcon16X16); + } + } + + export const yourIconNameStyles = css` + :host { + --ni-nimble-icon-layer-1-color: ${colorToken1}; + --ni-nimble-icon-layer-2-color: ${colorToken2}; + } + `; + + registerMultiColorIcon( + 'icon-your-icon-name', + IconYourIconName, + yourIconNameStyles + ); + export const iconYourIconNameTag = 'nimble-icon-your-icon-name'; + ``` + + The CSS custom properties map to SVG classes: `--ni-nimble-icon-layer-1-color` sets the color for `cls-1`, `--ni-nimble-icon-layer-2-color` for `cls-2`, and so on. + + **Note:** Multi-color icons are placed in the `src/icons-multicolor/` directory (which is checked into source control) rather than `src/icons/` (which is generated). + +4. **The icon will be automatically exported** from `src/icons/all-icons.ts` when the icon generation script runs. + +**Example:** See `src/icons-multicolor/circle-partial-broken.ts` for a complete multi-color icon implementation. + +**Note:** Multi-color icons do not support the `severity` attribute, as each layer has its own theme color token. + ### Export component tag Every component should export its custom element tag (e.g. `nimble-button`) in a constant like this: diff --git a/packages/nimble-components/build/generate-icons/source/index.js b/packages/nimble-components/build/generate-icons/source/index.js index 170b771ccb..4f05243752 100644 --- a/packages/nimble-components/build/generate-icons/source/index.js +++ b/packages/nimble-components/build/generate-icons/source/index.js @@ -3,9 +3,12 @@ * * Iterates through icons provided by nimble-tokens, and generates a Nimble component for each in * src/icons. Also generates an all-icons barrel file. + * + * Note: Multi-color icons should be created manually in src/icons-multicolor. + * See CONTRIBUTING.md for instructions. */ import { pascalCase, spinalCase } from '@ni/fast-web-utilities'; -import * as icons from '@ni/nimble-tokens/dist/icons/js'; +import * as icons from '@ni/nimble-tokens/dist/icons/js/single'; const fs = require('fs'); const path = require('path'); @@ -38,13 +41,14 @@ for (const key of Object.keys(icons)) { const svgName = key; // e.g. "arrowExpanderLeft16X16" const iconName = trimSizeFromName(key); // e.g. "arrowExpanderLeft" const fileName = spinalCase(iconName); // e.g. "arrow-expander-left"; + const elementBaseName = `icon-${spinalCase(iconName)}`; // e.g. "icon-arrow-expander-left-icon" const elementName = `nimble-${elementBaseName}`; const className = `Icon${pascalCase(iconName)}`; // e.g. "IconArrowExpanderLeft" const tagName = `icon${pascalCase(iconName)}Tag`; // e.g. "iconArrowExpanderLeftTag" const componentFileContents = `${generatedFilePrefix} -import { ${svgName} } from '@ni/nimble-tokens/dist/icons/js'; +import { ${svgName} } from '@ni/nimble-tokens/dist/icons/js/single'; import { Icon, registerIcon } from '../icon-base'; declare global { @@ -74,7 +78,25 @@ export const ${tagName} = '${elementName}'; `export { ${className} } from './${fileName}';\n` ); } -console.log(`Finshed writing ${fileCount} icon component files`); +console.log(`Finished writing ${fileCount} icon component files`); + +// Add manual icons to all-icons exports (from icons-multicolor directory) +const iconsMulticolorDirectory = path.resolve( + __dirname, + '../../../src/icons-multicolor' +); +if (fs.existsSync(iconsMulticolorDirectory)) { + const manualIconFiles = fs + .readdirSync(iconsMulticolorDirectory) + .filter(f => f.endsWith('.ts')); + for (const file of manualIconFiles) { + const fileName = path.basename(file, '.ts'); + const className = `Icon${pascalCase(fileName)}`; + allIconsFileContents = allIconsFileContents.concat( + `export { ${className} } from '../icons-multicolor/${fileName}';\n` + ); + } +} const allIconsFilePath = path.resolve(iconsDirectory, 'all-icons.ts'); console.log('Writing all-icons file'); diff --git a/packages/nimble-components/copilot-instructions.md b/packages/nimble-components/copilot-instructions.md new file mode 100644 index 0000000000..d06ded6a00 --- /dev/null +++ b/packages/nimble-components/copilot-instructions.md @@ -0,0 +1,108 @@ +# Nimble Components – AI Instructions + +## Key References + +- [`CONTRIBUTING.md`](../../CONTRIBUTING.md) (repo) – build/test/change workflows. +- [`packages/nimble-components/CONTRIBUTING.md`](CONTRIBUTING.md) – component lifecycle, Storybook, accessibility. +- [`docs/css-guidelines.md`](docs/css-guidelines.md) – cascade layers, `display()` utility, attribute-driven states. +- [`docs/coding-conventions.md`](docs/coding-conventions.md) – const-object enums, comment expectations. + +## Component Skeleton + +### `index.ts` + +```typescript +import { attr } from '@ni/fast-element'; +import { DesignSystem, FoundationElement } from '@ni/fast-foundation'; +import { styles } from './styles'; +import { template } from './template'; + +declare global { + interface HTMLElementTagNameMap { + 'nimble-example': Example; + } +} + +export class Example extends FoundationElement { + @attr({ attribute: 'my-attribute' }) + public myAttribute?: string; +} + +const nimbleExample = Example.compose({ + baseName: 'example', + baseClass: FoundationElement, + template, + styles +}); + +DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleExample()); +export const exampleTag = 'nimble-example'; +``` + +- Always export the tag constant and update `src/all-components.ts` so bundles include the component. +- Extend the FAST base (`baseClass`) whenever one exists; otherwise extend `FoundationElement`. +- Add `tabIndex` reflection and `shadowOptions.delegatesFocus` when components contain focusable internals. + +### `styles.ts` + +```typescript +import { css } from '@ni/fast-element'; +import { display } from '../utilities/style/display'; +import { bodyFont } from '../theme-provider/design-tokens'; + +export const styles = css` + @layer base, hover, focusVisible, active, disabled, top + + ${display('flex')} + + @layer base { + :host { + font: ${bodyFont}; + } + } +`; +``` + +- Use design tokens; never hardcode `var(--ni-nimble-*)` names. +- Organize selectors by document order per `docs/css-guidelines.md`. +- Prefer attribute selectors/behaviors to drive state instead of classes. + +### `tests/*.spec.ts` + +```typescript +import { html } from '@ni/fast-element'; +import { fixture, type Fixture } from '../../utilities/tests/fixture'; +import { Example, exampleTag } from '..'; + +describe('Example', () => { + async function setup(): Promise> { + return fixture(html`<${exampleTag}>`); + } + + it('constructs a nimble-example', () => { + expect(document.createElement(exampleTag)).toBeInstanceOf(Example); + }); + + it('updates when attribute changes', async () => { + const { element, connect, disconnect } = await setup(); + await connect(); + + element.setAttribute('my-attribute', 'value'); + + expect(element.myAttribute).toBe('value'); + await disconnect(); + }); +}); +``` + +- Use the fixture helpers for lifecycle management; disconnect in tests to prevent leaks. +- Tag browser-specific skips with `#SkipChrome|Firefox|Webkit` and include an issue link. + +## Development Checklist + +- Create `index.ts`, `styles.ts`, `template.ts`, `types.ts` (const-object enums only), `tests/`, and `stories/` as required by the package CONTRIBUTING guide. +- Register the component with the proper prefix (`nimble`, `spright`, `ok`) and export the tag constant. +- Add Storybook artifacts: `*.stories.ts`, `*-matrix.stories.ts`, and `*.mdx`. +- Update label-provider metadata and component status stories when APIs change. +- **Testing**: Always use `fdescribe` or `fit` to focus on relevant test suites before running `npm run tdd -w @ni/nimble-components`. The full test suite takes too long and may have unrelated failures. +- Run `npm run tdd:watch -w @ni/nimble-components`, `npm run storybook`, and `npm run format` before sending revisions. diff --git a/packages/nimble-components/src/breadcrumb-item/index.ts b/packages/nimble-components/src/breadcrumb-item/index.ts index a94b5f453d..88a1e6a6aa 100644 --- a/packages/nimble-components/src/breadcrumb-item/index.ts +++ b/packages/nimble-components/src/breadcrumb-item/index.ts @@ -4,7 +4,7 @@ import { breadcrumbItemTemplate as template, type BreadcrumbItemOptions } from '@ni/fast-foundation'; -import { forwardSlash16X16 } from '@ni/nimble-tokens/dist/icons/js'; +import { forwardSlash16X16 } from '@ni/nimble-tokens/dist/icons/js/single'; import { styles } from './styles'; declare global { diff --git a/packages/nimble-components/src/checkbox/index.ts b/packages/nimble-components/src/checkbox/index.ts index 38ef40612b..892b0bdc6b 100644 --- a/packages/nimble-components/src/checkbox/index.ts +++ b/packages/nimble-components/src/checkbox/index.ts @@ -4,7 +4,7 @@ import { Checkbox as FoundationCheckbox, type CheckboxOptions } from '@ni/fast-foundation'; -import { check16X16, minus16X16 } from '@ni/nimble-tokens/dist/icons/js'; +import { check16X16, minus16X16 } from '@ni/nimble-tokens/dist/icons/js/single'; import { styles } from './styles'; import { template } from './template'; import { mixinErrorPattern } from '../patterns/error/types'; diff --git a/packages/nimble-components/src/icon-base/icon-multicolor-metadata.ts b/packages/nimble-components/src/icon-base/icon-multicolor-metadata.ts new file mode 100644 index 0000000000..9020f48bc9 --- /dev/null +++ b/packages/nimble-components/src/icon-base/icon-multicolor-metadata.ts @@ -0,0 +1,11 @@ +/** + * Metadata for multi-color icons. + * This list is used by build scripts in nimble-components, angular-workspace, + * and react-workspace to identify which icons should not be auto-generated. + * + * Note: This list must be kept in sync with the multi-color SVGs in + * packages/nimble-tokens/dist/icons/svg-multicolor. + */ +export const multiColorIcons = ['circle-partial-broken'] as const; + +export type MultiColorIconName = (typeof multiColorIcons)[number]; diff --git a/packages/nimble-components/src/icon-base/index.ts b/packages/nimble-components/src/icon-base/index.ts index 90da606b6b..142726195a 100644 --- a/packages/nimble-components/src/icon-base/index.ts +++ b/packages/nimble-components/src/icon-base/index.ts @@ -1,10 +1,14 @@ -import { attr } from '@ni/fast-element'; +import { attr, type ElementStyles, type ViewTemplate } from '@ni/fast-element'; import { DesignSystem, FoundationElement } from '@ni/fast-foundation'; -import type { NimbleIcon } from '@ni/nimble-tokens/dist/icons/js'; import { template } from './template'; import { styles } from './styles'; import type { IconSeverity } from './types'; +export interface NimbleIcon { + name: string; + data: string; +} + /** * The base class for icon components */ @@ -17,18 +21,42 @@ export class Icon extends FoundationElement { @attr public severity: IconSeverity; - public constructor(/** @internal */ public readonly icon: NimbleIcon) { + /** @internal */ + public readonly icon: NimbleIcon; + + public constructor(icon: NimbleIcon) { super(); + this.icon = icon; } } type IconClass = typeof Icon; -export const registerIcon = (baseName: string, iconClass: IconClass): void => { +/** + * Register an icon component + * + * @param baseName - The base name for the icon element (e.g., 'icon-check') + * @param iconClass - The Icon class to register + * @param customTemplate - Optional custom template to use instead of the default + * @param additionalStyles - Optional additional styles to compose with the base styles + */ +export const registerIcon = ( + baseName: string, + iconClass: IconClass, + customTemplate?: ViewTemplate, + additionalStyles?: ElementStyles | ElementStyles[] +): void => { + let extraStyles: ElementStyles[] = []; + if (additionalStyles) { + extraStyles = Array.isArray(additionalStyles) + ? additionalStyles + : [additionalStyles]; + } + const composedIcon = iconClass.compose({ baseName, - template, - styles + template: customTemplate ?? template, + styles: additionalStyles ? [styles, ...extraStyles] : styles }); DesignSystem.getOrCreate().withPrefix('nimble').register(composedIcon()); diff --git a/packages/nimble-components/src/icon-base/multi-color-styles.ts b/packages/nimble-components/src/icon-base/multi-color-styles.ts new file mode 100644 index 0000000000..7b61c64fb9 --- /dev/null +++ b/packages/nimble-components/src/icon-base/multi-color-styles.ts @@ -0,0 +1,28 @@ +import { css } from '@ni/fast-element'; +import { iconColor } from '../theme-provider/design-tokens'; + +export const multiColorStyles = css` + .icon svg .cls-1 { + fill: var(--ni-nimble-icon-layer-1-color, ${iconColor}); + } + + .icon svg .cls-2 { + fill: var(--ni-nimble-icon-layer-2-color, ${iconColor}); + } + + .icon svg .cls-3 { + fill: var(--ni-nimble-icon-layer-3-color, ${iconColor}); + } + + .icon svg .cls-4 { + fill: var(--ni-nimble-icon-layer-4-color, ${iconColor}); + } + + .icon svg .cls-5 { + fill: var(--ni-nimble-icon-layer-5-color, ${iconColor}); + } + + .icon svg .cls-6 { + fill: var(--ni-nimble-icon-layer-6-color, ${iconColor}); + } +`; diff --git a/packages/nimble-components/src/icon-base/multi-color.ts b/packages/nimble-components/src/icon-base/multi-color.ts new file mode 100644 index 0000000000..14dd525355 --- /dev/null +++ b/packages/nimble-components/src/icon-base/multi-color.ts @@ -0,0 +1,58 @@ +import type { ElementStyles } from '@ni/fast-element'; +import { Icon, registerIcon, type NimbleIcon } from '.'; +import { multiColorStyles } from './multi-color-styles'; + +// Note: This constant is duplicated in packages/nimble-tokens/build/validate-icons.cjs +// Please ensure both are updated if this value changes. +export const MAX_ICON_LAYERS = 6; + +/** + * Base class for multi-color icon components. + * + * @public + * @remarks + * Multi-color icons use multiple theme colors for different visual regions + * instead of a single severity-based color. Each icon defines its own + * static styles that set CSS custom properties for layer colors. + * + * @example + * ```ts + * export class IconCirclePartialBroken extends MultiColorIcon { + * public constructor() { + * super(circlePartialBroken16X16); + * } + * } + * + * export const circlePartialBrokenStyles = css` + * :host { + * --ni-nimble-icon-layer-1-color: ${graphGridlineColor}; + * --ni-nimble-icon-layer-2-color: ${warningColor}; + * } + * `; + * + * registerMultiColorIcon('icon-circle-partial-broken', IconCirclePartialBroken, circlePartialBrokenStyles); + * ``` + */ +export class MultiColorIcon extends Icon { + public constructor(icon: NimbleIcon) { + super(icon); + } +} + +/** + * Register a multi-color icon component + * + * @param baseName - The base name for the icon element (e.g., 'icon-check') + * @param iconClass - The Icon class to register + * @param additionalStyles - Optional additional styles to compose with the base styles + */ +export const registerMultiColorIcon = ( + baseName: string, + iconClass: typeof MultiColorIcon, + additionalStyles?: ElementStyles +): void => { + const styles = additionalStyles + ? [multiColorStyles, additionalStyles] + : multiColorStyles; + registerIcon(baseName, iconClass, undefined, styles); +}; diff --git a/packages/nimble-components/src/icon-base/styles.ts b/packages/nimble-components/src/icon-base/styles.ts index dfb3b12b4a..f875c54ccb 100644 --- a/packages/nimble-components/src/icon-base/styles.ts +++ b/packages/nimble-components/src/icon-base/styles.ts @@ -42,8 +42,8 @@ export const styles = css` .icon svg { display: inline-flex; - fill: ${iconColor}; width: 100%; height: 100%; + fill: ${iconColor}; } `; diff --git a/packages/nimble-components/src/icon-base/tests/icon-metadata.ts b/packages/nimble-components/src/icon-base/tests/icon-metadata.ts index bbefa73abb..475bc86d18 100644 --- a/packages/nimble-components/src/icon-base/tests/icon-metadata.ts +++ b/packages/nimble-components/src/icon-base/tests/icon-metadata.ts @@ -1,13 +1,33 @@ +/** + * Icon metadata for Storybook search tags and testing. + * + * SINGLE SOURCE OF TRUTH: + * - Icon tags are manually maintained in this file + * - Multi-color icon list is imported from icon-multicolor-metadata + * to avoid duplication and ensure consistency across build scripts and metadata + */ +import { multiColorIcons } from '../icon-multicolor-metadata'; import type * as IconsNamespace from '../../icons/all-icons'; type IconName = keyof typeof IconsNamespace; interface IconMetadata { tags: string[]; + multiColor?: boolean; } -export const iconMetadata: { - readonly [key in IconName]: IconMetadata; +// Helper to determine if an icon is multi-color based on its class name +const isMultiColorIcon = (iconClassName: string): boolean => { + // Convert IconCirclePartialBroken -> circle-partial-broken + const iconName = iconClassName + .replace(/^Icon/, '') // Remove 'Icon' prefix + .replace(/([a-z])([A-Z])/g, '$1-$2') // Insert hyphens: aB -> a-B + .toLowerCase(); + return multiColorIcons.includes(iconName as never); +}; + +const iconMetadataBase: { + readonly [key in IconName]: Omit; } = { /* eslint-disable @typescript-eslint/naming-convention */ IconAdd: { @@ -719,3 +739,16 @@ export const iconMetadata: { } /* eslint-enable @typescript-eslint/naming-convention */ }; + +// Add multiColor flags based on nimble-tokens metadata +export const iconMetadata: { + readonly [key in IconName]: IconMetadata; +} = Object.fromEntries( + Object.entries(iconMetadataBase).map(([iconClassName, metadata]) => [ + iconClassName, + { + ...metadata, + ...(isMultiColorIcon(iconClassName) && { multiColor: true }) + } + ]) +) as { readonly [key in IconName]: IconMetadata }; diff --git a/packages/nimble-components/src/icon-base/tests/icons.spec.ts b/packages/nimble-components/src/icon-base/tests/icons.spec.ts index e981b2e1a9..5251c32fcc 100644 --- a/packages/nimble-components/src/icon-base/tests/icons.spec.ts +++ b/packages/nimble-components/src/icon-base/tests/icons.spec.ts @@ -1,4 +1,5 @@ -import * as nimbleIconsMap from '@ni/nimble-tokens/dist/icons/js'; +import * as singleIcons from '@ni/nimble-tokens/dist/icons/js/single'; +import * as multiColorIcons from '@ni/nimble-tokens/dist/icons/js/multicolor'; import { html } from '@ni/fast-element'; import { parameterizeSpec } from '@ni/jasmine-parameterized'; import * as allIconsNamespace from '../../icons/all-icons'; @@ -6,6 +7,8 @@ import { iconMetadata } from './icon-metadata'; import { type Fixture, fixture } from '../../utilities/tests/fixture'; import { IconAdd, iconAddTag } from '../../icons/add'; +const nimbleIconsMap = { ...singleIcons, ...multiColorIcons }; + describe('Icons', () => { const nimbleIcons = Object.values(nimbleIconsMap); const getSVGElement = (htmlString: string): SVGElement => { diff --git a/packages/nimble-components/src/icon-base/tests/multi-color-icons.spec.ts b/packages/nimble-components/src/icon-base/tests/multi-color-icons.spec.ts new file mode 100644 index 0000000000..f9883979c3 --- /dev/null +++ b/packages/nimble-components/src/icon-base/tests/multi-color-icons.spec.ts @@ -0,0 +1,246 @@ +import { circlePartialBroken16X16 } from '@ni/nimble-tokens/dist/icons/js/multicolor'; +import { html } from '@ni/fast-element'; +import { type Fixture, fixture } from '../../utilities/tests/fixture'; +import { + IconCirclePartialBroken, + iconCirclePartialBrokenTag +} from '../../icons-multicolor/circle-partial-broken'; +import { IconAdd, iconAddTag } from '../../icons/add'; +import { Icon } from '..'; +import { MultiColorIcon, MAX_ICON_LAYERS } from '../multi-color'; + +describe('Multi-color icons', () => { + describe('IconCirclePartialBroken', () => { + async function setup(): Promise> { + return await fixture( + html`<${iconCirclePartialBrokenTag}>` + ); + } + + let element: IconCirclePartialBroken; + let connect: () => Promise; + let disconnect: () => Promise; + + beforeEach(async () => { + ({ element, connect, disconnect } = await setup()); + }); + + afterEach(async () => { + await disconnect(); + }); + + it('can be constructed', () => { + expect( + document.createElement(iconCirclePartialBrokenTag) + ).toBeInstanceOf(IconCirclePartialBroken); + }); + + it('should apply layer colors as CSS custom properties on host', async () => { + await connect(); + + const computedStyle = getComputedStyle(element); + const layer1Color = computedStyle + .getPropertyValue('--ni-nimble-icon-layer-1-color') + .trim(); + const layer2Color = computedStyle + .getPropertyValue('--ni-nimble-icon-layer-2-color') + .trim(); + + // Verify custom properties resolve to color values (not empty) + expect(layer1Color).toBeTruthy(); + expect(layer2Color).toBeTruthy(); + // Verify they resolve to different colors + expect(layer1Color).not.toBe(layer2Color); + }); + + it('should persist layer colors across disconnect/reconnect', async () => { + await connect(); + + const layer1Before = getComputedStyle(element).getPropertyValue( + '--ni-nimble-icon-layer-1-color' + ); + const layer2Before = getComputedStyle(element).getPropertyValue( + '--ni-nimble-icon-layer-2-color' + ); + + await disconnect(); + await connect(); + + const layer1After = getComputedStyle(element).getPropertyValue( + '--ni-nimble-icon-layer-1-color' + ); + const layer2After = getComputedStyle(element).getPropertyValue( + '--ni-nimble-icon-layer-2-color' + ); + + expect(layer1After).toBe(layer1Before); + expect(layer2After).toBe(layer2Before); + }); + + it('should render SVG with correct structure', async () => { + await connect(); + + const iconDiv = element.shadowRoot!.querySelector('.icon')!; + expect(iconDiv.innerHTML).toContain(' { + await connect(); + + const iconDiv = element.shadowRoot!.querySelector('.icon'); + expect(iconDiv?.getAttribute('aria-hidden')).toBe('true'); + }); + + it('should be accessible via tag name', () => { + const tagName = customElements.getName(IconCirclePartialBroken); + expect(tagName).toBe(iconCirclePartialBrokenTag); + }); + }); + + describe('Regular icons (non-multi-color)', () => { + async function setup(): Promise> { + return await fixture( + html`<${iconAddTag}>` + ); + } + + let element: IconAdd; + let connect: () => Promise; + let disconnect: () => Promise; + + beforeEach(async () => { + ({ element, connect, disconnect } = await setup()); + }); + + afterEach(async () => { + await disconnect(); + }); + + it('should not be a MultiColorIcon', async () => { + await connect(); + + expect(element instanceof MultiColorIcon).toBe(false); + }); + + it('should not have layer color CSS properties on host', async () => { + await connect(); + + const computedStyle = getComputedStyle(element); + expect( + computedStyle.getPropertyValue('--ni-nimble-icon-layer-1-color') + ).toBe(''); + expect( + computedStyle.getPropertyValue('--ni-nimble-icon-layer-2-color') + ).toBe(''); + }); + + it('should not be affected by multi-color logic', async () => { + await connect(); + + const iconDiv = element.shadowRoot!.querySelector('.icon')!; + const innerHTML = iconDiv.innerHTML; + + expect(innerHTML).toContain(' { + it('should extend Icon', () => { + const icon = new IconCirclePartialBroken(); + expect(icon).toBeInstanceOf(Icon); + expect(icon).toBeInstanceOf(MultiColorIcon); + }); + + it('should preserve icon property from base class', () => { + const icon = new IconCirclePartialBroken(); + expect(icon.icon).toBe(circlePartialBroken16X16); + }); + + it('should respect MAX_ICON_LAYERS limit', () => { + // Verify the constant is set to expected value + // The limit is enforced at build time by the validation script + expect(MAX_ICON_LAYERS).toBe(6); + }); + }); + + describe('MAX_ICON_LAYERS constant', () => { + it('should be defined and equal to 6', () => { + expect(MAX_ICON_LAYERS).toBe(6); + }); + }); + + describe('Integration with DOM', () => { + it('should render multi-color icon in DOM', async () => { + const { element, connect, disconnect } = await fixture( + html`<${iconCirclePartialBrokenTag}>` + ); + + await connect(); + + expect(element.isConnected).toBe(true); + expect(element.shadowRoot).toBeTruthy(); + + const iconDiv = element.shadowRoot!.querySelector('.icon'); + expect(iconDiv).toBeTruthy(); + + await disconnect(); + }); + + it('should support multiple instances on same page', async () => { + const { + element: element1, + connect: connect1, + disconnect: disconnect1 + } = await fixture( + html`<${iconCirclePartialBrokenTag}>` + ); + + const { + element: element2, + connect: connect2, + disconnect: disconnect2 + } = await fixture( + html`<${iconCirclePartialBrokenTag}>` + ); + + await connect1(); + await connect2(); + + const iconDiv1 = element1.shadowRoot!.querySelector('.icon')!; + const iconDiv2 = element2.shadowRoot!.querySelector('.icon')!; + + expect(iconDiv1).toBeDefined(); + expect(iconDiv2).toBeDefined(); + + // Both instances should have layer colors set on host + const layer1Color1 = getComputedStyle(element1) + .getPropertyValue('--ni-nimble-icon-layer-1-color') + .trim(); + const layer1Color2 = getComputedStyle(element2) + .getPropertyValue('--ni-nimble-icon-layer-1-color') + .trim(); + + // Verify both instances have the layer color set and they match + expect(layer1Color1).toBeTruthy(); + expect(layer1Color2).toBeTruthy(); + expect(layer1Color1).toBe(layer1Color2); + + await disconnect1(); + await disconnect2(); + }); + }); + + describe('Icon base class functionality', () => { + it('should preserve Icon base class properties', () => { + const icon = new IconCirclePartialBroken(); + + // Should have Icon properties + expect(icon.icon).toBeDefined(); + expect(icon.icon).toBe(circlePartialBroken16X16); + + // Should have severity attribute support (from Icon base) + expect(icon.severity).toBeUndefined(); // Not set by default + }); + }); +}); diff --git a/packages/nimble-components/src/icons-multicolor/circle-partial-broken.ts b/packages/nimble-components/src/icons-multicolor/circle-partial-broken.ts new file mode 100644 index 0000000000..906b0d585c --- /dev/null +++ b/packages/nimble-components/src/icons-multicolor/circle-partial-broken.ts @@ -0,0 +1,49 @@ +// Note: This icon file is manually created, not generated by the icon build script. +// For instructions on creating multi-color icons, see CONTRIBUTING.md +import { circlePartialBroken16X16 } from '@ni/nimble-tokens/dist/icons/js/multicolor'; +import { css } from '@ni/fast-element'; +import { + MultiColorIcon, + registerMultiColorIcon +} from '../icon-base/multi-color'; +import type { NimbleIcon } from '../icon-base'; +import { + bodyDisabledFontColor, + warningColor +} from '../theme-provider/design-tokens'; + +declare global { + interface HTMLElementTagNameMap { + 'nimble-icon-circle-partial-broken': IconCirclePartialBroken; + } +} + +/** + * A multi-color icon component for the 'circlePartialBroken' icon. + * This icon uses two theme colors: + * - cls-1: bodyDisabledFontColor (circle outline) + * - cls-2: warningColor (broken segment) + */ +export class IconCirclePartialBroken extends MultiColorIcon { + public constructor() { + super(circlePartialBroken16X16 as NimbleIcon); + } +} + +/** + * Static styles for the circle-partial-broken multi-color icon. + * Each layer color is set as a CSS custom property on the :host element. + */ +export const circlePartialBrokenStyles = css` + :host { + --ni-nimble-icon-layer-1-color: ${bodyDisabledFontColor}; + --ni-nimble-icon-layer-2-color: ${warningColor}; + } +`; + +registerMultiColorIcon( + 'icon-circle-partial-broken', + IconCirclePartialBroken, + circlePartialBrokenStyles +); +export const iconCirclePartialBrokenTag = 'nimble-icon-circle-partial-broken'; diff --git a/packages/nimble-components/src/menu-item/index.ts b/packages/nimble-components/src/menu-item/index.ts index 69beccb78c..0e0fcca638 100644 --- a/packages/nimble-components/src/menu-item/index.ts +++ b/packages/nimble-components/src/menu-item/index.ts @@ -4,7 +4,7 @@ import { menuItemTemplate as template, type MenuItemOptions } from '@ni/fast-foundation'; -import { arrowExpanderRight16X16 } from '@ni/nimble-tokens/dist/icons/js'; +import { arrowExpanderRight16X16 } from '@ni/nimble-tokens/dist/icons/js/single'; import { styles } from './styles'; // FAST menu item template requires an anchored region is available using tagFor DI diff --git a/packages/nimble-components/src/radio/index.ts b/packages/nimble-components/src/radio/index.ts index 23d0dd9ab2..74b123c262 100644 --- a/packages/nimble-components/src/radio/index.ts +++ b/packages/nimble-components/src/radio/index.ts @@ -4,7 +4,7 @@ import { DesignSystem, type RadioOptions } from '@ni/fast-foundation'; -import { circleFilled16X16 } from '@ni/nimble-tokens/dist/icons/js'; +import { circleFilled16X16 } from '@ni/nimble-tokens/dist/icons/js/single'; import { styles } from './styles'; declare global { diff --git a/packages/nimble-components/src/select/index.ts b/packages/nimble-components/src/select/index.ts index 59d0af6d8e..17de289123 100644 --- a/packages/nimble-components/src/select/index.ts +++ b/packages/nimble-components/src/select/index.ts @@ -22,7 +22,7 @@ import { keySpace, uniqueId } from '@ni/fast-web-utilities'; -import { arrowExpanderDown16X16 } from '@ni/nimble-tokens/dist/icons/js'; +import { arrowExpanderDown16X16 } from '@ni/nimble-tokens/dist/icons/js/single'; import { styles } from './styles'; import { DropdownAppearance, diff --git a/packages/nimble-components/src/tree-item/index.ts b/packages/nimble-components/src/tree-item/index.ts index df94d522f2..845ac975b1 100644 --- a/packages/nimble-components/src/tree-item/index.ts +++ b/packages/nimble-components/src/tree-item/index.ts @@ -5,7 +5,7 @@ import { DesignSystem, treeItemTemplate as template } from '@ni/fast-foundation'; -import { arrowExpanderUp16X16 } from '@ni/nimble-tokens/dist/icons/js'; +import { arrowExpanderUp16X16 } from '@ni/nimble-tokens/dist/icons/js/single'; import { styles } from './styles'; declare global { diff --git a/packages/nimble-components/src/tree-view/tests/tree.spec.ts b/packages/nimble-components/src/tree-view/tests/tree.spec.ts index 09b5d9764c..e264e43c0c 100644 --- a/packages/nimble-components/src/tree-view/tests/tree.spec.ts +++ b/packages/nimble-components/src/tree-view/tests/tree.spec.ts @@ -1,5 +1,5 @@ import { html, ref } from '@ni/fast-element'; -import { notebook16X16 } from '@ni/nimble-tokens/dist/icons/js'; +import { notebook16X16 } from '@ni/nimble-tokens/dist/icons/js/single'; import { keyEnter } from '@ni/fast-web-utilities'; import { fixture, type Fixture } from '../../utilities/tests/fixture'; import { clickElement } from '../../utilities/testing/component'; diff --git a/packages/nimble-tokens/.gitignore b/packages/nimble-tokens/.gitignore index 0c0b498543..7d4266c0b0 100644 --- a/packages/nimble-tokens/.gitignore +++ b/packages/nimble-tokens/.gitignore @@ -1,5 +1,6 @@ dist/icons/* -!dist/icons/svg +!dist/icons/svg-single +!dist/icons/svg-multicolor dist/fonts/scss diff --git a/packages/nimble-tokens/CONTRIBUTING.md b/packages/nimble-tokens/CONTRIBUTING.md index 784d4aea91..d349d94fb9 100644 --- a/packages/nimble-tokens/CONTRIBUTING.md +++ b/packages/nimble-tokens/CONTRIBUTING.md @@ -67,13 +67,13 @@ These steps require access to Adobe Illustrator and Perforce so will typically b 1. Search for all `.*` tags in the exported `.svg` files and remove them. This removes all color from the `.svg` files and allows us to dynamically change the fill color. - + - **Note:** In rare cases, icons will be provided with multiple fixed colors that are not intended to change with the theme or `severity`. These icons should retain the `` tags. - + - For icons that need multiple theme colors, see the **Creating Multi-Color Icons** section in `/packages/nimble-components/CONTRIBUTING.md`. In the SVG, assign sequential CSS classes (`cls-1`, `cls-2`, etc.) to regions that should use different theme colors. 2. Confirm the new icon files will build correctly by running: `npm run build -w @ni/nimble-tokens`. 3. Generate and build icon components by running `npm run build -w @ni/nimble-components`. This step will report an error at this point but is necessary to enable the next step. -4. Add metadata for the new icons to `nimble-components/src/icon-base/tests/icon-metadata.ts`. +4. Add metadata for the new icons to `nimble-components/src/icon-base/tests/icon-metadata.ts`. If the icon uses multiple color layers, also add its spinal-case name to `nimble-components/src/icon-base/icon-multicolor-metadata.ts` so the build scripts treat it as a multi-color icon. 5. Run `npm run build -w @ni/nimble-components` again. It should now succeed. -6. Preview the built files by running: `npm run storybook`, and review the **Icons** story to confirm that your changes appear correctly. Inspect the icons in each **Severity** and ensure their color changes. +6. Preview the built files by running: `npm run storybook`, and review the **Icons** story. Verify single‑color icons change with **Severity** and multi‑color icons render their layers as intended in light/dark themes. 7. Publish a PR with your changes. If there are any new icons, set `changeType` and `dependentChangeType` to minor in the beachball change file. diff --git a/packages/nimble-tokens/build/validate-icons.cjs b/packages/nimble-tokens/build/validate-icons.cjs new file mode 100644 index 0000000000..88605fd29f --- /dev/null +++ b/packages/nimble-tokens/build/validate-icons.cjs @@ -0,0 +1,64 @@ +const fs = require('fs'); +const path = require('path'); + +// Note: This constant is duplicated in packages/nimble-components/src/icon-base/multi-color.ts +// Please ensure both are updated if this value changes. +const MAX_ICON_LAYERS = 6; +const multiColorDir = path.resolve(__dirname, '../dist/icons/svg-multicolor'); +const singleColorDir = path.resolve(__dirname, '../dist/icons/svg-single'); + +function countLayersInSvg(svgContent) { + const classMatches = svgContent.match(/class\s*=\s*["']cls-\d+["']/g); + if (!classMatches) { + return 0; + } + const classNumbers = classMatches.map(match => { + const num = match.match(/\d+/); + return num ? parseInt(num[0], 10) : 0; + }); + return Math.max(...classNumbers, 0); +} + +function validateMultiColorIcons() { + if (!fs.existsSync(multiColorDir)) { + console.log('No multi-color icons directory found. Skipping validation.'); + return; + } + + const files = fs.readdirSync(multiColorDir).filter(f => f.endsWith('.svg')); + let hasError = false; + + console.log(`Validating ${files.length} multi-color icons...`); + + for (const file of files) { + const filePath = path.resolve(multiColorDir, file); + const content = fs.readFileSync(filePath, 'utf-8'); + const layers = countLayersInSvg(content); + + if (layers > MAX_ICON_LAYERS) { + console.error(`ERROR: ${file} has ${layers} layers. Max allowed is ${MAX_ICON_LAYERS}.`); + hasError = true; + } + + if (layers <= 1) { + console.warn(`WARNING: ${file} has ${layers} layers. Should it be in single-color icons?`); + } + } + + if (hasError) { + process.exit(1); + } +} + +function validateSingleColorIcons() { + if (!fs.existsSync(singleColorDir)) { + console.log('No single-color icons directory found. Skipping validation.'); + } + + // Optional: Check if single color icons accidentally have multi-color classes + // This might be too strict if we use cls-1 for single color too, but usually single color icons don't use classes for fill. +} + +validateMultiColorIcons(); +validateSingleColorIcons(); +console.log('Icon validation passed.'); diff --git a/packages/nimble-tokens/dist/icons/svg/circle-partial-broken_16x16.svg b/packages/nimble-tokens/dist/icons/svg-multicolor/circle-partial-broken_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/circle-partial-broken_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-multicolor/circle-partial-broken_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/Clipboard_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/Clipboard_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/Clipboard_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/Clipboard_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/Clock_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/Clock_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/Clock_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/Clock_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/Filter_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/Filter_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/Filter_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/Filter_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/Home_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/Home_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/Home_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/Home_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/Link_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/Link_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/Link_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/Link_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/Markdown__16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/Markdown__16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/Markdown__16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/Markdown__16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/Notebook_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/Notebook_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/Notebook_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/Notebook_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/Tag_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/Tag_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/Tag_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/Tag_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/add_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/add_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/add_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/add_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-down-left-and-arrow-up-right_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-down-left-and-arrow-up-right_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-down-left-and-arrow-up-right_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-down-left-and-arrow-up-right_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-down-rectangle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-down-rectangle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-down-rectangle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-down-rectangle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-down-right-and-arrow-up-left_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-down-right-and-arrow-up-left_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-down-right-and-arrow-up-left_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-down-right-and-arrow-up-left_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-down-two-rectangles.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-down-two-rectangles.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-down-two-rectangles.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-down-two-rectangles.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-down_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-down_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-down_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-down_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-expander-down_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-expander-down_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-expander-down_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-expander-down_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-expander-left_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-expander-left_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-expander-left_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-expander-left_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-expander-right_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-expander-right_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-expander-right_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-expander-right_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-expander-up_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-expander-up_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-expander-up_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-expander-up_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-in-circle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-in-circle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-in-circle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-in-circle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-left-from-line_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-left-from-line_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-left-from-line_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-left-from-line_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-left-two-rectangles.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-left-two-rectangles.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-left-two-rectangles.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-left-two-rectangles.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-out-circle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-out-circle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-out-circle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-out-circle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-partial-rotate-left_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-partial-rotate-left_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-partial-rotate-left_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-partial-rotate-left_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-right-thin_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-right-thin_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-right-thin_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-right-thin_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-right-to-line_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-right-to-line_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-right-to-line_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-right-to-line_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-right-two-rectangles.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-right-two-rectangles.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-right-two-rectangles.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-right-two-rectangles.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-rotate-right_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-rotate-right_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-rotate-right_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-rotate-right_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-u-left_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-u-left_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-u-left_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-u-left_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-u-right_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-u-right_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-u-right_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-u-right_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-u-up_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-u-up_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-u-up_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-u-up_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-up-left-and-arrow-down-right_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-up-left-and-arrow-down-right_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-up-left-and-arrow-down-right_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-up-left-and-arrow-down-right_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-up-rectangle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-up-rectangle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-up-rectangle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-up-rectangle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-up-right-and-arrow-down-left_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-up-right-and-arrow-down-left_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-up-right-and-arrow-down-left_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-up-right-and-arrow-down-left_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-up-right-from-square_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-up-right-from-square_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-up-right-from-square_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-up-right-from-square_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-up-two-rectangles.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-up-two-rectangles.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-up-two-rectangles.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-up-two-rectangles.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrow-up_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrow-up_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrow-up_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrow-up_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrows-maximize_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrows-maximize_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrows-maximize_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrows-maximize_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrows-repeat_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrows-repeat_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrows-repeat_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrows-repeat_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/arrows-rotate-reverse-dot_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/arrows-rotate-reverse-dot_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/arrows-rotate-reverse-dot_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/arrows-rotate-reverse-dot_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/asterisk_5x5.svg b/packages/nimble-tokens/dist/icons/svg-single/asterisk_5x5.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/asterisk_5x5.svg rename to packages/nimble-tokens/dist/icons/svg-single/asterisk_5x5.svg diff --git a/packages/nimble-tokens/dist/icons/svg/at_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/at_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/at_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/at_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/bars_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/bars_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/bars_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/bars_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/bell-and-comment_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/bell-and-comment_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/bell-and-comment_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/bell-and-comment_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/bell-and-message_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/bell-and-message_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/bell-and-message_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/bell-and-message_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/bell-check_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/bell-check_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/bell-check_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/bell-check_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/bell-circle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/bell-circle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/bell-circle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/bell-circle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/bell-on_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/bell-on_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/bell-on_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/bell-on_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/bell-solid-circle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/bell-solid-circle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/bell-solid-circle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/bell-solid-circle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/bell_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/bell_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/bell_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/bell_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/block-with-ribbon_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/block-with-ribbon_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/block-with-ribbon_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/block-with-ribbon_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/bold-b_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/bold-b_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/bold-b_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/bold-b_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/book_magnifying_glass_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/book_magnifying_glass_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/book_magnifying_glass_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/book_magnifying_glass_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/calendar-arrows-rotate-reverse-dot_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/calendar-arrows-rotate-reverse-dot_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/calendar-arrows-rotate-reverse-dot_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/calendar-arrows-rotate-reverse-dot_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/calendar-check-lines_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/calendar-check-lines_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/calendar-check-lines_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/calendar-check-lines_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/calendar-circle-exclamation_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/calendar-circle-exclamation_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/calendar-circle-exclamation_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/calendar-circle-exclamation_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/calendar-clock_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/calendar-clock_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/calendar-clock_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/calendar-clock_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/calendar-day-outline_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/calendar-day-outline_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/calendar-day-outline_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/calendar-day-outline_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/calendar-day_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/calendar-day_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/calendar-day_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/calendar-day_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/calendar-days_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/calendar-days_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/calendar-days_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/calendar-days_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/calendar-lines_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/calendar-lines_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/calendar-lines_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/calendar-lines_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/calendar-rectangle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/calendar-rectangle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/calendar-rectangle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/calendar-rectangle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/calendar-week_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/calendar-week_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/calendar-week_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/calendar-week_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/calipers_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/calipers_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/calipers_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/calipers_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/camera_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/camera_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/camera_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/camera_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/chart-diagram-child-focus_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/chart-diagram-child-focus_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/chart-diagram-child-focus_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/chart-diagram-child-focus_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/chart-diagram-parent-focus-two-child_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/chart-diagram-parent-focus-two-child_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/chart-diagram-parent-focus-two-child_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/chart-diagram-parent-focus-two-child_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/chart-diagram-parent-focus_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/chart-diagram-parent-focus_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/chart-diagram-parent-focus_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/chart-diagram-parent-focus_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/chart-diagram_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/chart-diagram_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/chart-diagram_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/chart-diagram_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/check-dot_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/check-dot_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/check-dot_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/check-dot_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/check_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/check_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/check_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/check_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/circle-broken_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/circle-broken_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/circle-broken_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/circle-broken_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/circle-check_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/circle-check_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/circle-check_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/circle-check_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/circle-minus_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/circle-minus_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/circle-minus_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/circle-minus_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/circle-slash_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/circle-slash_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/circle-slash_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/circle-slash_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/circle-x_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/circle-x_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/circle-x_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/circle-x_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/circle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/circle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/circle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/circle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/circle_filled_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/circle_filled_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/circle_filled_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/circle_filled_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/clock-cog_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/clock-cog_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/clock-cog_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/clock-cog_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/clock-exclamation_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/clock-exclamation_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/clock-exclamation_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/clock-exclamation_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/clock-triangle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/clock-triangle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/clock-triangle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/clock-triangle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/clone_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/clone_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/clone_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/clone_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/cloud-upload_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/cloud-upload_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/cloud-upload_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/cloud-upload_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/cloud-with-arrow_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/cloud-with-arrow_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/cloud-with-arrow_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/cloud-with-arrow_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/cloud_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/cloud_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/cloud_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/cloud_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/cog-database-inset_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/cog-database-inset_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/cog-database-inset_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/cog-database-inset_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/cog-database_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/cog-database_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/cog-database_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/cog-database_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/cog-small-cog_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/cog-small-cog_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/cog-small-cog_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/cog-small-cog_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/cog-zoomed_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/cog-zoomed_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/cog-zoomed_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/cog-zoomed_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/cog_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/cog_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/cog_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/cog_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/comment_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/comment_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/comment_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/comment_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/computer-and-monitor_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/computer-and-monitor_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/computer-and-monitor_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/computer-and-monitor_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/copy-text_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/copy-text_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/copy-text_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/copy-text_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/copy_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/copy_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/copy_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/copy_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/dashboard-builder-legend_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/dashboard-builder-legend_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/dashboard-builder-legend_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/dashboard-builder-legend_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/dashboard-builder-templates_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/dashboard-builder-templates_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/dashboard-builder-templates_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/dashboard-builder-templates_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/dashboard-builder-tile_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/dashboard-builder-tile_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/dashboard-builder-tile_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/dashboard-builder-tile_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/dashboard-builder_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/dashboard-builder_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/dashboard-builder_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/dashboard-builder_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/database-check_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/database-check_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/database-check_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/database-check_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/database_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/database_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/database_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/database_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/debug_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/debug_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/debug_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/debug_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/desktop_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/desktop_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/desktop_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/desktop_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/diadem_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/diadem_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/diadem_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/diadem_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/donut-chart_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/donut-chart_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/donut-chart_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/donut-chart_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/dot-solid-dot-stroke-measurement_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/dot-solid-dot-stroke-measurement_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/dot-solid-dot-stroke-measurement_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/dot-solid-dot-stroke-measurement_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/dot-solid-dot-stroke_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/dot-solid-dot-stroke_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/dot-solid-dot-stroke_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/dot-solid-dot-stroke_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/down-right-from-square_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/down-right-from-square_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/down-right-from-square_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/down-right-from-square_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/download_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/download_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/download_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/download_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/electronic-chip-zoomed_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/electronic-chip-zoomed_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/electronic-chip-zoomed_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/electronic-chip-zoomed_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/exclamation-mark_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/exclamation-mark_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/exclamation-mark_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/exclamation-mark_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/eye-dash_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/eye-dash_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/eye-dash_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/eye-dash_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/eye_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/eye_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/eye_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/eye_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/fancy-a_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/fancy-a_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/fancy-a_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/fancy-a_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/file-arrow-curved-right_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/file-arrow-curved-right_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/file-arrow-curved-right_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/file-arrow-curved-right_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/file-drawer_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/file-drawer_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/file-drawer_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/file-drawer_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/file-search_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/file-search_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/file-search_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/file-search_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/file_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/file_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/file_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/file_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/floppy-disk-checkmark_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/floppy-disk-checkmark_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/floppy-disk-checkmark_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/floppy-disk-checkmark_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/floppy-disk-pen_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/floppy-disk-pen_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/floppy-disk-pen_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/floppy-disk-pen_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/floppy-disk-star-arrow-right_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/floppy-disk-star-arrow-right_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/floppy-disk-star-arrow-right_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/floppy-disk-star-arrow-right_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/floppy-disk-three-dots_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/floppy-disk-three-dots_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/floppy-disk-three-dots_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/floppy-disk-three-dots_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/floppy-disk_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/floppy-disk_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/floppy-disk_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/floppy-disk_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/folder-open_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/folder-open_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/folder-open_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/folder-open_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/folder_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/folder_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/folder_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/folder_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/forward-slash_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/forward-slash_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/forward-slash_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/forward-slash_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/four-dots-square_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/four-dots-square_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/four-dots-square_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/four-dots-square_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/function_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/function_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/function_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/function_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/gauge-simple_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/gauge-simple_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/gauge-simple_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/gauge-simple_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/grid-three-by-three_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/grid-three-by-three_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/grid-three-by-three_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/grid-three-by-three_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/grid-two-by-two_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/grid-two-by-two_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/grid-two-by-two_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/grid-two-by-two_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/hammer_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/hammer_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/hammer_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/hammer_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/hashtag_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/hashtag_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/hashtag_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/hashtag_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/horizontal-triangle-outline_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/horizontal-triangle-outline_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/horizontal-triangle-outline_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/horizontal-triangle-outline_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/hourglass_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/hourglass_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/hourglass_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/hourglass_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/indent_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/indent_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/indent_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/indent_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/indeterminant-checkbox_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/indeterminant-checkbox_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/indeterminant-checkbox_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/indeterminant-checkbox_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/info-circle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/info-circle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/info-circle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/info-circle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/info_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/info_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/info_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/info_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/inward-squares-three_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/inward-squares-three_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/inward-squares-three_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/inward-squares-three_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/italic-i_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/italic-i_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/italic-i_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/italic-i_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/key_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/key_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/key_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/key_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/laptop_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/laptop_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/laptop_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/laptop_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/layer-group_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/layer-group_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/layer-group_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/layer-group_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/lightbulb_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/lightbulb_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/lightbulb_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/lightbulb_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/lightning-bolt_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/lightning-bolt_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/lightning-bolt_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/lightning-bolt_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/link-cancel_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/link-cancel_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/link-cancel_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/link-cancel_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/list-tree-database_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/list-tree-database_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/list-tree-database_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/list-tree-database_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/list-tree_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/list-tree_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/list-tree_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/list-tree_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/list_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/list_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/list_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/list_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/lock_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/lock_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/lock_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/lock_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/magnifying-glass_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/magnifying-glass_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/magnifying-glass_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/magnifying-glass_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/message-bot_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/message-bot_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/message-bot_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/message-bot_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/message_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/message_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/message_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/message_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/messages-sparkle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/messages-sparkle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/messages-sparkle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/messages-sparkle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/microphone_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/microphone_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/microphone_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/microphone_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/minus-wide_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/minus-wide_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/minus-wide_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/minus-wide_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/minus_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/minus_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/minus_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/minus_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/mobile_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/mobile_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/mobile_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/mobile_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/mountain-sun_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/mountain-sun_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/mountain-sun_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/mountain-sun_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/ni_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/ni_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/ni_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/ni_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/number-list_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/number-list_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/number-list_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/number-list_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/outdent_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/outdent_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/outdent_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/outdent_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/outward-squares-three_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/outward-squares-three_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/outward-squares-three_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/outward-squares-three_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/paper-plane_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/paper-plane_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/paper-plane_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/paper-plane_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/paperclip_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/paperclip_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/paperclip_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/paperclip_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/paste_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/paste_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/paste_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/paste_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/pause_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/pause_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/pause_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/pause_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/pencil-to-rectangle.svg b/packages/nimble-tokens/dist/icons/svg-single/pencil-to-rectangle.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/pencil-to-rectangle.svg rename to packages/nimble-tokens/dist/icons/svg-single/pencil-to-rectangle.svg diff --git a/packages/nimble-tokens/dist/icons/svg/pencil_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/pencil_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/pencil_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/pencil_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/play.svg b/packages/nimble-tokens/dist/icons/svg-single/play.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/play.svg rename to packages/nimble-tokens/dist/icons/svg-single/play.svg diff --git a/packages/nimble-tokens/dist/icons/svg/pot_with_lid_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/pot_with_lid_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/pot_with_lid_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/pot_with_lid_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/print.svg b/packages/nimble-tokens/dist/icons/svg-single/print.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/print.svg rename to packages/nimble-tokens/dist/icons/svg-single/print.svg diff --git a/packages/nimble-tokens/dist/icons/svg/qrcode-read.svg b/packages/nimble-tokens/dist/icons/svg-single/qrcode-read.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/qrcode-read.svg rename to packages/nimble-tokens/dist/icons/svg-single/qrcode-read.svg diff --git a/packages/nimble-tokens/dist/icons/svg/question_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/question_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/question_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/question_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/rectangle-check-lines_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/rectangle-check-lines_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/rectangle-check-lines_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/rectangle-check-lines_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/rectangle-lines_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/rectangle-lines_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/rectangle-lines_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/rectangle-lines_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/running-arrow_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/running-arrow_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/running-arrow_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/running-arrow_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/scanner-gun_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/scanner-gun_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/scanner-gun_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/scanner-gun_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/screen-check-lines-calendar_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/screen-check-lines-calendar_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/screen-check-lines-calendar_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/screen-check-lines-calendar_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/screen-check-lines_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/screen-check-lines_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/screen-check-lines_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/screen-check-lines_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/server_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/server_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/server_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/server_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/share-nodes_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/share-nodes_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/share-nodes_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/share-nodes_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/shield-check_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/shield-check_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/shield-check_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/shield-check_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/shield-xmark_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/shield-xmark_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/shield-xmark_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/shield-xmark_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/signal-bars_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/signal-bars_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/signal-bars_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/signal-bars_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/sine-graph_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/sine-graph_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/sine-graph_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/sine-graph_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/skip-arrow_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/skip-arrow_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/skip-arrow_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/skip-arrow_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/sparkle-swirls_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/sparkle-swirls_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/sparkle-swirls_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/sparkle-swirls_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/sparkles_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/sparkles_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/sparkles_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/sparkles_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/spinner.svg b/packages/nimble-tokens/dist/icons/svg-single/spinner.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/spinner.svg rename to packages/nimble-tokens/dist/icons/svg-single/spinner.svg diff --git a/packages/nimble-tokens/dist/icons/svg/square-check_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/square-check_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/square-check_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/square-check_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/square-list-cog_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/square-list-cog_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/square-list-cog_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/square-list-cog_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/square-t_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/square-t_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/square-t_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/square-t_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/square-x_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/square-x_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/square-x_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/square-x_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/star-8-point_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/star-8-point_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/star-8-point_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/star-8-point_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/stop-square_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/stop-square_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/stop-square_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/stop-square_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/systemlink_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/systemlink_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/systemlink_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/systemlink_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/t_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/t_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/t_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/t_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/tablet_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/tablet_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/tablet_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/tablet_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/tags_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/tags_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/tags_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/tags_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/target-crosshairs-progress_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/target-crosshairs-progress_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/target-crosshairs-progress_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/target-crosshairs-progress_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/target-crosshairs_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/target-crosshairs_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/target-crosshairs_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/target-crosshairs_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/three-circles-ascending-container_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/three-circles-ascending-container_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/three-circles-ascending-container_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/three-circles-ascending-container_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/three-dots-line_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/three-dots-line_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/three-dots-line_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/three-dots-line_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/three-vertical-lines_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/three-vertical-lines_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/three-vertical-lines_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/three-vertical-lines_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/thumb-down_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/thumb-down_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/thumb-down_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/thumb-down_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/thumb-up_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/thumb-up_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/thumb-up_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/thumb-up_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/thumbtack_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/thumbtack_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/thumbtack_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/thumbtack_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/tile-size_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/tile-size_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/tile-size_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/tile-size_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/times_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/times_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/times_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/times_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/trash_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/trash_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/trash_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/trash_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/triangle-filled_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/triangle-filled_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/triangle-filled_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/triangle-filled_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/triangle-two-lines-horizontal.svg b/packages/nimble-tokens/dist/icons/svg-single/triangle-two-lines-horizontal.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/triangle-two-lines-horizontal.svg rename to packages/nimble-tokens/dist/icons/svg-single/triangle-two-lines-horizontal.svg diff --git a/packages/nimble-tokens/dist/icons/svg/triangle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/triangle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/triangle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/triangle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/true-false-rectangle_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/true-false-rectangle_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/true-false-rectangle_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/true-false-rectangle_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/two-squares-in-brackets.svg b/packages/nimble-tokens/dist/icons/svg-single/two-squares-in-brackets.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/two-squares-in-brackets.svg rename to packages/nimble-tokens/dist/icons/svg-single/two-squares-in-brackets.svg diff --git a/packages/nimble-tokens/dist/icons/svg/two-triangles-between-lines.svg b/packages/nimble-tokens/dist/icons/svg-single/two-triangles-between-lines.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/two-triangles-between-lines.svg rename to packages/nimble-tokens/dist/icons/svg-single/two-triangles-between-lines.svg diff --git a/packages/nimble-tokens/dist/icons/svg/unlink_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/unlink_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/unlink_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/unlink_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/unlock_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/unlock_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/unlock_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/unlock_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/up-right-from-square_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/up-right-from-square_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/up-right-from-square_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/up-right-from-square_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/upload_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/upload_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/upload_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/upload_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/user_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/user_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/user_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/user_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/watch_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/watch_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/watch_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/watch_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/waveform_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/waveform_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/waveform_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/waveform_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/webvi-custom_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/webvi-custom_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/webvi-custom_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/webvi-custom_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/webvi-host_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/webvi-host_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/webvi-host_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/webvi-host_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/window-code_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/window-code_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/window-code_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/window-code_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/window-dock_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/window-dock_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/window-dock_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/window-dock_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/window-restore_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/window-restore_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/window-restore_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/window-restore_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/window-text_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/window-text_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/window-text_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/window-text_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/wrench-hammer_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/wrench-hammer_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/wrench-hammer_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/wrench-hammer_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/xmark-check_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/xmark-check_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/xmark-check_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/xmark-check_16x16.svg diff --git a/packages/nimble-tokens/dist/icons/svg/xmark_16x16.svg b/packages/nimble-tokens/dist/icons/svg-single/xmark_16x16.svg similarity index 100% rename from packages/nimble-tokens/dist/icons/svg/xmark_16x16.svg rename to packages/nimble-tokens/dist/icons/svg-single/xmark_16x16.svg diff --git a/packages/nimble-tokens/package.json b/packages/nimble-tokens/package.json index c550b3ea82..6c9b5c99f8 100644 --- a/packages/nimble-tokens/package.json +++ b/packages/nimble-tokens/package.json @@ -3,9 +3,12 @@ "version": "8.13.2", "description": "Design tokens for the NI Nimble Design System", "scripts": { - "build": "npm run build:svg-to-ts && npm run build:ts && npm run build:generate-font-scss && npm run build:style-dictionary", - "build:svg-to-ts": "svg-to-ts-constants --config ./svg-to-ts-config.json", + "build": "npm run build:svg-to-ts && npm run build:ts && npm run build:generate-font-scss && npm run build:style-dictionary && npm run validate-icons", + "build:svg-to-ts": "npm run build:svg-to-ts:single && npm run build:svg-to-ts:multicolor", + "build:svg-to-ts:single": "svg-to-ts-constants --config ./svg-to-ts-config-single.json", + "build:svg-to-ts:multicolor": "svg-to-ts-constants --config ./svg-to-ts-config-multicolor.json", "build:generate-font-scss": "node build/generate-font-scss.cjs", + "validate-icons": "node build/validate-icons.cjs", "build:style-dictionary": "cd source/styledictionary && node build.js", "build:ts": "tsc -p ./tsconfig.json", "build:ts:watch": "tsc -p ./tsconfig.json -w", diff --git a/packages/nimble-tokens/svg-to-ts-config-multicolor.json b/packages/nimble-tokens/svg-to-ts-config-multicolor.json new file mode 100644 index 0000000000..b87fe15e46 --- /dev/null +++ b/packages/nimble-tokens/svg-to-ts-config-multicolor.json @@ -0,0 +1,25 @@ +{ + "srcFiles": [ + "./dist/icons/svg-multicolor/*.svg" + ], + "prefix": "", + "svgoConfig": { + "plugins": [ + { + "name": "preset-default", + "params": { + "overrides": { + "removeUnknownsAndDefaults": { + "keepDataAttrs": false + } + } + } + } + ] + }, + "fileName": "index", + "outputDirectory": "./dist/icons/ts/multicolor", + "interfaceName": "NimbleIcon", + "typeName": "NimbleIconName", + "exportCompleteIconSet": false +} diff --git a/packages/nimble-tokens/svg-to-ts-config.json b/packages/nimble-tokens/svg-to-ts-config-single.json similarity index 85% rename from packages/nimble-tokens/svg-to-ts-config.json rename to packages/nimble-tokens/svg-to-ts-config-single.json index d837e486b1..1edd6caa9e 100644 --- a/packages/nimble-tokens/svg-to-ts-config.json +++ b/packages/nimble-tokens/svg-to-ts-config-single.json @@ -1,7 +1,6 @@ - { "srcFiles": [ - "./dist/icons/svg/*.svg" + "./dist/icons/svg-single/*.svg" ], "prefix": "", "svgoConfig": { @@ -19,7 +18,7 @@ ] }, "fileName": "index", - "outputDirectory": "./dist/icons/ts/", + "outputDirectory": "./dist/icons/ts/single", "interfaceName": "NimbleIcon", "typeName": "NimbleIconName", "exportCompleteIconSet": false diff --git a/packages/react-workspace/nimble-react/build/generate-icons/README.md b/packages/react-workspace/nimble-react/build/generate-icons/README.md new file mode 100644 index 0000000000..67f01404e7 --- /dev/null +++ b/packages/react-workspace/nimble-react/build/generate-icons/README.md @@ -0,0 +1,16 @@ +# Generate Icons + +## Behavior + +- Depends on the build output of `nimble-tokens` to generate React wrapper components for icons. +- Generates a React wrapper file for each icon in `src/icons/`. +- **Automatically handles multi-color icons** by detecting them from nimble-components metadata and using the appropriate import path (`icons-multicolor` vs `icons`). + +## How to run + +This script runs as part of the Nimble React build. + +To run manually: + +1. Run a Nimble React build. +2. Edit `index.js` for this script and run `npm run build:icons` (can re-run when modifying `index.js` behavior). diff --git a/packages/react-workspace/nimble-react/build/generate-icons/source/index.js b/packages/react-workspace/nimble-react/build/generate-icons/source/index.js index 60af163b9a..db0939eb33 100644 --- a/packages/react-workspace/nimble-react/build/generate-icons/source/index.js +++ b/packages/react-workspace/nimble-react/build/generate-icons/source/index.js @@ -2,7 +2,11 @@ * Build script for generating React wrappers for Nimble icon components. */ import { pascalCase, spinalCase } from '@ni/fast-web-utilities'; -import * as icons from '@ni/nimble-tokens/dist/icons/js'; +import * as singleIcons from '@ni/nimble-tokens/dist/icons/js/single'; +import * as multiColorIconsData from '@ni/nimble-tokens/dist/icons/js/multicolor'; +import { multiColorIcons } from '@ni/nimble-components/dist/esm/icon-base/icon-multicolor-metadata'; + +const icons = { ...singleIcons, ...multiColorIconsData }; const fs = require('fs'); const path = require('path'); @@ -15,6 +19,9 @@ const trimSizeFromName = text => { const generatedFilePrefix = `// AUTO-GENERATED FILE - DO NOT EDIT DIRECTLY // See generation source in nimble-react/build/generate-icons\n`; +// Multi-color icons use a different import path (icons-multicolor vs icons) +const multiColorIconSet = new Set(multiColorIcons); + const iconsDirectory = path.resolve(__dirname, '../../../src/icons'); if (fs.existsSync(iconsDirectory)) { @@ -33,12 +40,17 @@ let fileCount = 0; for (const key of Object.keys(icons)) { const iconName = trimSizeFromName(key); // e.g. "arrowExpanderLeft" const fileName = spinalCase(iconName); // e.g. "arrow-expander-left"; + + // Determine if this is a multi-color icon and set the appropriate import path + const isMultiColor = multiColorIconSet.has(fileName); + const iconSubfolder = isMultiColor ? 'icons-multicolor' : 'icons'; + const className = `Icon${pascalCase(iconName)}`; // e.g. "IconArrowExpanderLeft" fileCount += 1; const iconReactWrapperContent = `${generatedFilePrefix} -import { ${className} } from '@ni/nimble-components/dist/esm/icons/${fileName}'; +import { ${className} } from '@ni/nimble-components/dist/esm/${iconSubfolder}/${fileName}'; import { wrap } from '../utilities/react-wrapper'; export { type ${className} }; diff --git a/packages/storybook/src/nimble/icon-base/icons.stories.ts b/packages/storybook/src/nimble/icon-base/icons.stories.ts index 14295132ab..180280fd48 100644 --- a/packages/storybook/src/nimble/icon-base/icons.stories.ts +++ b/packages/storybook/src/nimble/icon-base/icons.stories.ts @@ -20,12 +20,32 @@ import { } from '../../utilities/storybook'; type IconName = keyof typeof nimbleIconComponentsMap; -const data = Object.entries(nimbleIconComponentsMap).map( - ([iconClassName, iconClass]) => ({ - tag: customElements.getName(iconClass), + +// Force evaluation of all icon exports at module load time to trigger registerIcon() calls +// This ensures icons are registered before any data is created +Object.values(nimbleIconComponentsMap); + +const data = Object.entries(nimbleIconComponentsMap).map(([iconClassName]) => { + // For multi-color icons, the actual registered class is a wrapper created by + // createMultiColorIconClass, so customElements.getName(iconClass) returns undefined. + // Instead, derive the tag name from the class name. + // IconCirclePartialBroken -> icon-circle-partial-broken -> nimble-icon-circle-partial-broken + const iconName = iconClassName.replace(/^Icon/, ''); // Remove 'Icon' prefix + const kebabCase = iconName + // Insert hyphen before uppercase letters that follow lowercase/digits: aB -> a-B, 8P -> 8-P + .replace(/([a-z0-9])([A-Z])/g, '$1-$2') + // Insert hyphen before uppercase letters that follow uppercase and precede lowercase: ABc -> A-Bc + .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2') + // Insert hyphen before digits that follow letters: a8 -> a-8 + .replace(/([a-zA-Z])(\d)/g, '$1-$2') + .toLowerCase(); + const tag = `nimble-icon-${kebabCase}`; + + return { + tag, metaphor: iconMetadata[iconClassName as IconName].tags.join(', ') - }) -); + }; +}); type Data = (typeof data)[number]; diff --git a/packages/storybook/src/spright/chat/conversation/story-helpers.ts b/packages/storybook/src/spright/chat/conversation/story-helpers.ts index cbff8f0f7b..2d78819d5a 100644 --- a/packages/storybook/src/spright/chat/conversation/story-helpers.ts +++ b/packages/storybook/src/spright/chat/conversation/story-helpers.ts @@ -1,4 +1,4 @@ -import { webviCustom16X16 } from '@ni/nimble-tokens/dist/icons/js'; +import { webviCustom16X16 } from '@ni/nimble-tokens/dist/icons/js/single'; const imgBlob = new Blob([webviCustom16X16.data], { type: 'image/svg+xml'