Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1153
diff -u -p -r1.1153 common.inc
--- includes/common.inc	28 Apr 2010 20:25:20 -0000	1.1153
+++ includes/common.inc	28 Apr 2010 22:58:16 -0000
@@ -3908,24 +3908,31 @@ function drupal_process_attached($elemen
  *   - irrelevant
  *   - expanded
  *   - readwrite
- *
  *   Each of these states is an array containing conditions that must be met in
  *   order for this state to be active. The key to this conditioning array is
  *   a jQuery selector for the element that is checked. The value of the
  *   conditioning array are the states that are checked on the element (empty,
  *   checked, value, collapsed, etc) and the expected value of that condition.
- *
  *   @code
  *   $form['email_canceled']['settings'] = array(
  *     '#type' => 'container',
  *     '#states' => array(
  *       // Hide the settings when the cancel notify checkbox is disabled.
  *       'invisible' => array(
- *         'input[name="email_canceled_toggle"]' => array('checked' => FALSE),
+ *         ':input[name="email_canceled_toggle"]' => array('checked' => FALSE),
  *       ),
  *     ),
  *   );
  *   @endcode
+ *   Note that you need to use a 'value' condition for radio buttons:
+ *   @code
+ *     '#states' => array(
+ *       // Show the settings if 'bar' has been selected for 'foo'.
+ *       'visible' => array(
+ *         ':input[name="foo"]' => array('value' => 'bar'),
+ *       ),
+ *     ),
+ *   @endcode
  */
 function drupal_process_states(&$elements) {
   $elements['#attached']['js']['misc/states.js'] = array('weight' => JS_LIBRARY + 1);
Index: misc/states.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/states.js,v
retrieving revision 1.2
diff -u -p -r1.2 states.js
--- misc/states.js	18 Feb 2010 19:24:55 -0000	1.2
+++ misc/states.js	28 Apr 2010 22:54:39 -0000
@@ -247,11 +247,22 @@ states.Trigger.states = {
     }
   },
 
+  // For radio buttons, only return the value if the radio button is selected.
   value: {
     'keyup': function () {
+      // Radio buttons share the same :input[name="key"] selector.
+      if (this.length > 1) {
+        // Initial checked value of radios is undefined, so we return false.
+        return this.filter(':checked').val() || false;
+      }
       return this.val();
     },
     'change': function () {
+      // Radio buttons share the same :input[name="key"] selector.
+      if (this.length > 1) {
+        // Initial checked value of radios is undefined, so we return false.
+        return this.filter(':checked').val() || false;
+      }
       return this.val();
     }
   },
Index: modules/simpletest/tests/form_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form_test.module,v
retrieving revision 1.39
diff -u -p -r1.39 form_test.module
--- modules/simpletest/tests/form_test.module	28 Apr 2010 16:11:22 -0000	1.39
+++ modules/simpletest/tests/form_test.module	28 Apr 2010 23:02:44 -0000
@@ -22,14 +22,12 @@ function form_test_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('form_test_validate_form'),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
   $items['form-test/limit-validation-errors'] = array(
     'title' => 'Form validation with some error suppression',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('form_test_limit_validation_errors_form'),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
 
   $items['form_test/tableselect/multiple-true'] = array(
@@ -37,28 +35,24 @@ function form_test_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('_form_test_tableselect_multiple_true_form'),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
   $items['form_test/tableselect/multiple-false'] = array(
     'title' => 'Tableselect radio button test',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('_form_test_tableselect_multiple_false_form'),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
   $items['form_test/tableselect/empty-text'] = array(
     'title' => 'Tableselect empty text test',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('_form_test_tableselect_empty_form'),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
   $items['form_test/tableselect/advanced-select'] = array(
     'title' => 'Tableselect js_select tests',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('_form_test_tableselect_js_select_form'),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
 
   $items['form_test/form-storage'] = array(
@@ -66,7 +60,6 @@ function form_test_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('form_test_storage_form'),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
 
   $items['form_test/wrapper-callback'] = array(
@@ -74,7 +67,6 @@ function form_test_menu() {
     'page callback' => 'form_test_wrapper_callback',
     'page arguments' => array('form_test_wrapper_callback_form'),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
 
   $items['form_test/form-state-values-clean'] = array(
@@ -82,23 +74,20 @@ function form_test_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('form_test_form_state_values_clean_form'),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
 
   $items['form-test/checkbox'] = array(
-    'title' => t('Form test'),
+    'title' => t('Form test: Checkbox'),
     'page callback' => 'drupal_get_form',
     'page arguments' => array('_form_test_checkbox'),
     'access callback' => TRUE,
-    'type' => MENU_CALLBACK,
   );
 
   $items['form-test/disabled-elements'] = array(
-    'title' => t('Form test'),
+    'title' => t('Form test: Disabled Elements'),
     'page callback' => 'drupal_get_form',
     'page arguments' => array('_form_test_disabled_elements'),
     'access callback' => TRUE,
-    'type' => MENU_CALLBACK,
   );
 
   $items['form-test/form-rebuild-preserve-values'] = array(
@@ -106,7 +95,6 @@ function form_test_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('form_test_form_rebuild_preserve_values_form'),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
 
   $items['form_test/form-labels'] = array(
@@ -114,7 +102,6 @@ function form_test_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('form_label_test_form'),
     'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
   );
 
   $items['form-test/state-persist'] = array(
@@ -122,7 +109,6 @@ function form_test_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('form_test_state_persist'),
     'access callback' => TRUE,
-    'type' => MENU_CALLBACK,
   );
 
   $items['form-test/clicked-button'] = array(
@@ -130,7 +116,13 @@ function form_test_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('form_test_clicked_button'),
     'access callback' => TRUE,
-    'type' => MENU_CALLBACK,
+  );
+
+  $items['form-test/states'] = array(
+    'title' => '#states demonstration',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_test_states'),
+    'access callback' => TRUE,
   );
 
   if (module_exists('node')) {
@@ -141,7 +133,6 @@ function form_test_menu() {
       'access arguments' => array('create', 'page'),
       'file path' => drupal_get_path('module', 'node'),
       'file' => 'node.pages.inc',
-      'type' => MENU_CALLBACK,
     );
   }
 
@@ -1135,3 +1126,36 @@ function form_test_two_instances() {
   $return['node_form_2'] = drupal_get_form('page_node_form', $node2);
   return $return;
 }
+
+/**
+ * Form constructor to demonstrate and manually test #states.
+ */
+function form_test_states($form, &$form_state) {
+  $form['radios'] = array(
+    '#type' => 'radios',
+    '#title' => 'Choose your destiny',
+    '#options' => array(
+      'one' => 'First',
+      'two' => 'Second',
+    ),
+  );
+  $form['input_1'] = array(
+    '#type' => 'textfield',
+    '#title' => 'Only shown when radio button with value "one" is selected',
+    '#states' => array(
+      'visible' => array(
+        ':input[name="radios"]' => array('value' => 'one'),
+      ),
+    ),
+  );
+  $form['input_2'] = array(
+    '#type' => 'textfield',
+    '#title' => 'Only shown when radio button with value "two" is selected',
+    '#states' => array(
+      'visible' => array(
+        ':input[name="radios"]' => array('value' => 'two'),
+      ),
+    ),
+  );
+  return $form;
+}
