Skip to content

Conversation

@gmjgeek
Copy link

@gmjgeek gmjgeek commented Aug 31, 2025

A framework-agnostic view model for a language chooser.

The goal of this project is to make it easy to create a language chooser in any reactive framework (React, Svelte, Vue, etc).

TODO:

  • Support custom language options
  • Expose "ready to submit" field
  • Implement Svelte adaptor for Field class
  • Build a demo Svelte app
  • Highlight search results
  • Support translation through Crowdin
  • Add warning/info icons
Screenshot 2025-09-20 at 8 30 48 PM

This change is Reviewable

Copy link

@imnasnainaec imnasnainaec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 19 files reviewed, all discussions resolved


components/language-chooser/common/language-chooser-controller/src/state-management/field.ts line 14 at r1 (raw file):

   * Callback to update the UI when the field changes
   */
  onUpdate: ((newValue: T) => void) | null = null;

What is onUpdate for? It's never set within this class (or even within this pr). Should it be explicitly public? Or made private and added to the constructor analogously to onUpdateRequested?


components/language-chooser/common/language-chooser-controller/src/selectable.ts line 10 at r1 (raw file):

  for (let i = 0; i < items.length; i++) {
    items[i].isSelected.value = i === index;
  }

What about something like

items.forEach((item, i) => {
  item.isSelected.value = i === index;
});

@gmjgeek
Copy link
Author

gmjgeek commented Sep 2, 2025

@imnasnainaec Thanks for the feedback. Field.onUpdate is now explicitly public. This callback is a mechanism for updating the UI, which I'm now starting to implement.

Copy link

@imnasnainaec imnasnainaec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imnasnainaec reviewed 3 of 34 files at r2, all commit messages.
Reviewable status: 3 of 54 files reviewed, all discussions resolved


components/language-chooser/common/language-chooser-controller/src/view-models/language-card.ts line 17 at r3 (raw file):

      if (onSelect) {
        onSelect(isSelected);
      }

This can be shortened to onSelect?.(isSelected);, though that's a stylistic choice.


components/language-chooser/common/language-chooser-controller/src/view-models/script-card.ts line 17 at r3 (raw file):

      if (onSelect) {
        onSelect(isSelected);
      }

This can be shortened to onSelect?.(isSelected);, though that's a stylistic choice.


components/state-management/state-management-core/src/field.ts line 29 at r3 (raw file):

    if (this._onUpdateRequested) {
      this._onUpdateRequested(value, oldValue);
    }

This can be shortened to this._onUpdateRequested?.(value, oldValue);, though that's a stylistic choice.


components/state-management/state-management-core/src/field.ts line 41 at r3 (raw file):

  public set value(value: T) {
    try {
      if (this.onUpdate) this.onUpdate(value);

This can be shortened to this.onUpdate?.(value);, though that's a stylistic choice.

@gmjgeek
Copy link
Author

gmjgeek commented Sep 21, 2025

The Svelte demo app is now functional and almost bug-free when run on the Vite development server. However, minification will likely break the app in production. Still making some changes.

@gmjgeek gmjgeek marked this pull request as ready for review September 29, 2025 17:11
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a framework-agnostic state management system for a language chooser component, including a core library, Svelte adapter, controller logic, and a demo application using DaisyUI.

Key Changes:

  • New state management core library with a Field class for reactive data binding
  • Svelte adapter that transforms vanilla view models into Svelte-compatible reactive properties
  • Language chooser controller with view models for language selection, script selection, and customization
  • Complete Svelte+DaisyUI implementation with demo application

Reviewed changes

Copilot reviewed 63 out of 64 changed files in this pull request and generated 22 comments.

Show a summary per file
File Description
package.json Added new workspace entries for state-management and svelte packages
nx.json Updated project list to include new packages in alphabetical order
eslint.config.mjs Added ignore patterns for vite/vitest timestamp files and fixed trailing comma
components/state-management/state-management-core/* Core state management library with Field class, tests, and documentation
components/state-management/state-management-svelte/* Svelte adapter for transforming view models with reactive fields
components/language-chooser/common/language-chooser-controller/* Framework-agnostic view models and logic for language selection
components/language-chooser/svelte/language-chooser-svelte-daisyui/* Svelte components and demo app using DaisyUI for styling
.vscode/extensions.json Added Prettier extension recommendation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

},
lib: {
entry: "./index.ts",
name: "@ethnolib/find-language",
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The library name in the vite config should be "@ethnolib/state-management-svelte" but it's currently set to "@ethnolib/find-language". This will cause incorrect naming in the built output.

Copilot uses AI. Check for mistakes.
function _appendLanguages(languages: ILanguage[]) {
const baseIndex = listedLanguages.value.length;
const newLanguages = languages.map((lang, i) =>
useLanguageChardViewModel(lang, {
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in function name: "useLanguageChardViewModel" should be "useLanguageCardViewModel" (missing 'a' in "Card"). This should match the corrected spelling in the function definition.

Copilot uses AI. Check for mistakes.
});

describe("selected script", () => {
it("should match scipt selection", () => {
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in "scipt" should be "script" (note: there's a typo in the test description).

Suggested change
it("should match scipt selection", () => {
it("should match script selection", () => {

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,108 @@
# State Management Core

This package provides a simple interface for working with multiple reactive framworks.
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in "framworks" should be "frameworks" (note: there's a typo in the README documentation).

Copilot uses AI. Check for mistakes.
},
lib: {
entry: "./index.ts",
name: "@ethnolib/find-language",
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The library name in the vite config should be "@ethnolib/state-management-core" but it's currently set to "@ethnolib/find-language". This will cause incorrect naming in the built output.

Copilot uses AI. Check for mistakes.

class TestHelper {
constructor(language: ILanguage) {
this.card = useLanguageChardViewModel(language);
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in function name: "useLanguageChardViewModel" should be "useLanguageCardViewModel" (missing 'a' in "Card"). This should match the corrected spelling in the function definition.

Copilot uses AI. Check for mistakes.
});
}

function submitCustomizeLangaugeModal({
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in function name: "submitCustomizeLangaugeModal" should be "submitCustomizeLanguageModal" (missing 'a' in "Language").

Suggested change
function submitCustomizeLangaugeModal({
function submitCustomizeLanguageModal({

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +27
"devDependencies": {
"@nx/vite": "^19.1.2",
"@types/node": "^20.16.11",
"svelte": "^5.38.6",
"svelte-check": "^4.0.0",
"@sveltejs/vite-plugin-svelte": "^4.0.0",
"tsx": "^4.19.2",
"typescript": "^5.2.2"
},
"volta": {
"extends": "../../../package.json"
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dependency: The package depends on "@ethnolib/state-management-core" but this is not listed in the dependencies or devDependencies. Add it to ensure the package can be properly installed and used.

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +24
"devDependencies": {
"@nx/vite": "^19.1.2",
"@types/node": "^20.16.11",
"tsx": "^4.19.2",
"typescript": "^5.2.2"
},
"volta": {
"extends": "../../../../package.json"
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dependencies: The package depends on "@ethnolib/find-language" and "@ethnolib/state-management-core" but these are not listed in the dependencies or devDependencies. Add them to ensure the package can be properly installed and used.

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +34
"devDependencies": {
"@nx/vite": "^20.4.6",
"@sveltejs/vite-plugin-svelte": "^6.1.4",
"@tailwindcss/postcss": "^4.1.13",
"@tailwindcss/typography": "^0.5.16",
"@tsconfig/svelte": "^5.0.0",
"autoprefixer": "^10.4.21",
"daisyui": "^5.1.12",
"eslint-plugin-svelte": "^2.44.0",
"postcss": "^8.5.6",
"svelte": "^5.38.6",
"svelte-check": "^4.0.5",
"svelte-preprocess": "^6.0.0",
"tailwindcss": "^3.4.17"
},
"engines": {
"node": ">=18.18"
},
"nx": {}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dependencies: The package depends on "@ethnolib/find-language", "@ethnolib/language-chooser-controller", and "@ethnolib/state-management-svelte" but these are not listed in the dependencies or devDependencies. Add them to ensure the package can be properly installed and used.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants