PageSourceSearch

https://cdn2.futurefund.com/assets/honey/forms/controllers/state_select_controller-b5e5dfab.js

js futurefund.com collected 2026-09-24 11:52:31 UTC 4,842 bytes, 181 lines download raw bytes

1/**
2 * @class StateSelectController
3 * @extends Controller
4 * @description
5 * Enhances state select dropdowns with US state name-to-abbreviation mapping.
6 * Works alongside the ChoicesController to handle autofill scenarios where
7 * password managers type full state names (e.g., "California") but the select
8 * options only contain abbreviations (e.g., "CA").
9 *
10 * The controller automatically finds the select element within its scope,
11 * so it can be placed on the wrapper div or the select element itself.
12 *
13 * @example <caption>State select with autofill support (on wrapper)</caption>
14 * <div data-controller="choices state-select">
15 *   <select data-choices-target="select" name="state">
16 *     <option value="">Select a state</option>
17 *     <option value="CA">CA</option>
18 *     <option value="NY">NY</option>
19 *   </select>
20 * </div>
21 *
22 * @example <caption>State select with controller on select element</caption>
23 * <div data-controller="choices">
24 *   <select data-controller="state-select" data-choices-target="select" name="state">
25 *     <option value="">Select a state</option>
26 *     <option value="CA">CA</option>
27 *   </select>
28 * </div>
29 */
30import { Controller } from "@hotwired/stimulus"
31
32/**
33 * Mapping of lowercase full state names to their 2-character abbreviations.
34 * Includes US states, DC, Puerto Rico, and the Armed Forces (AA, AE, AP) codes.
35 * @constant {Object.<string, string>}
36 */
37const STATE_NAME_TO_ABBR = {
38  'alabama': 'AL',
39  'alaska': 'AK',
40  'arizona': 'AZ',
41  'arkansas': 'AR',
42  'california': 'CA',
43  'colorado': 'CO',
44  'connecticut': 'CT',
45  'delaware': 'DE',
46  'district of columbia': 'DC',
47  'florida': 'FL',
48  'georgia': 'GA',
49  'hawaii': 'HI',
50  'idaho': 'ID',
51  'illinois': 'IL',
52  'indiana': 'IN',
53  'iowa': 'IA',
54  'kansas': 'KS',
55  'kentucky': 'KY',
56  'louisiana': 'LA',
57  'maine': 'ME',
58  'maryland': 'MD',
59  'massachusetts': 'MA',
60  'michigan': 'MI',
61  'minnesota': 'MN',
62  'mississippi': 'MS',
63  'missouri': 'MO',
64  'montana': 'MT',
65  'nebraska': 'NE',
66  'nevada': 'NV',
67  'new hampshire': 'NH',
68  'new jersey': 'NJ',
69  'new mexico': 'NM',
70  'new york': 'NY',
71  'north carolina': 'NC',
72  'north dakota': 'ND',
73  'ohio': 'OH',
74  'oklahoma': 'OK',
75  'oregon': 'OR',
76  'pennsylvania': 'PA',
77  'puerto rico': 'PR',
78  'rhode island': 'RI',
79  'south carolina': 'SC',
80  'south dakota': 'SD',
81  'tennessee': 'TN',
82  'texas': 'TX',
83  'utah': 'UT',
84  'vermont': 'VT',
85  'virginia': 'VA',
86  'washington': 'WA',
87  'west virginia': 'WV',
88  'wisconsin': 'WI',
89  'wyoming': 'WY',
90  'armed forces americas': 'AA',
91  'armed forces europe': 'AE',
92  'armed forces pacific': 'AP'
93}
94
95export default class StateSelectController extends Controller {
96  /**
97   * Bound reference to the type handler for cleanup.
98   * @type {Function|null}
99   * @private
100   */
101  boundHandleType = null
102
103  /**
104   * Reference to the select element.
105   * @type {HTMLSelectElement|null}
106   * @private
107   */
108  selectElement = null
109
110  /**
111   * Initializes the state name mapping on the Tom Select instance.
112   * Waits for Tom Select to be initialized by the ChoicesController.
113   *
114   * @method connect
115   * @returns {void}
116   */
117  connect() {
118    // Find the select element within this controller's scope
119    this.selectElement = this.element.querySelector('select') || this.element
120    if (this.selectElement.tagName !== 'SELECT') {
121      this.selectElement = null
122      return
123    }
124
125    // Wait for Tom Select to initialize (choices controller runs first)
126    requestAnimationFrame(() => {
127      this.attachTypeListener()
128    })
129  }
130
131  /**
132   * Attaches the type event listener to the Tom Select instance.
133   * Retries if Tom Select is not yet initialized.
134   *
135   * @method attachTypeListener
136   * @private
137   * @returns {void}
138   */
139  attachTypeListener() {
140    const ts = this.selectElement?.tomselect
141    if (ts) {
142      this.boundHandleType = this.handleType.bind(this)
143      ts.on('type', this.boundHandleType)
144    } else {
145      // Tom Select not ready yet, try again
146      requestAnimationFrame(() => this.attachTypeListener())
147    }
148  }
149
150  /**
151   * Handles type events from Tom Select.
152   * If the typed query matches a full state name, selects the corresponding abbreviation.
153   *
154   * @method handleType
155   * @param {string} query - The text being typed into the search input
156   * @returns {void}
157   */
158  handleType(query) {
159    const ts = this.selectElement?.tomselect
160    if (!ts) return
161
162    const abbr = STATE_NAME_TO_ABBR[query.toLowerCase()]
163    if (abbr && ts.options[abbr]) {
164      ts.setValue(abbr)
165      ts.close()
166    }
167  }
168
169  /**
170   * Cleans up event listeners when the controller disconnects.
171   *
172   * @method disconnect
173   * @returns {void}
174   */
175  disconnect() {
176    const ts = this.selectElement?.tomselect
177    if (ts && this.boundHandleType) {
178      ts.off('type', this.boundHandleType)
179    }
180  }
181}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.