From 61109e722acdff9f878dcb66cd1f82c8be4fa0dd Mon Sep 17 00:00:00 2001 From: automated-signal <37887102+automated-signal@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:09:11 -0500 Subject: [PATCH] Init AxoSearchField and AxoPasswordField Co-authored-by: Jamie <113370520+jamiebuilds-signal@users.noreply.github.com> --- _locales/en/messages.json | 4 + ts/axo/AxoTextField.dom.tsx | 627 -------------- ts/axo/_internal/AxoIntl.dom.tsx | 1 + ts/axo/_internal/StrictContext.dom.tsx | 14 + .../fields/AxoPasswordField.dom.stories.tsx | 24 + ts/axo/fields/AxoPasswordField.dom.tsx | 77 ++ ts/axo/fields/AxoSearchField.dom.stories.tsx | 21 + ts/axo/fields/AxoSearchField.dom.tsx | 46 + .../{ => fields}/AxoTextField.dom.stories.tsx | 12 +- ts/axo/fields/AxoTextField.dom.tsx | 243 ++++++ ts/axo/fields/_AxoBaseField.dom.tsx | 788 ++++++++++++++++++ ts/components/ProfileEditor.dom.tsx | 2 +- .../stages/CreatePIN.dom.tsx | 26 +- .../stages/CreatePINConfirm.dom.tsx | 27 +- .../stages/PhoneNumber.dom.tsx | 4 +- .../stages/ProfileEntry.dom.tsx | 6 +- .../stages/VerifyPIN.dom.tsx | 30 +- ts/windows/AppProvider.dom.tsx | 3 +- 18 files changed, 1271 insertions(+), 684 deletions(-) delete mode 100644 ts/axo/AxoTextField.dom.tsx create mode 100644 ts/axo/fields/AxoPasswordField.dom.stories.tsx create mode 100644 ts/axo/fields/AxoPasswordField.dom.tsx create mode 100644 ts/axo/fields/AxoSearchField.dom.stories.tsx create mode 100644 ts/axo/fields/AxoSearchField.dom.tsx rename ts/axo/{ => fields}/AxoTextField.dom.stories.tsx (97%) create mode 100644 ts/axo/fields/AxoTextField.dom.tsx create mode 100644 ts/axo/fields/_AxoBaseField.dom.tsx diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 8188301f87..39f70a9d90 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -27,6 +27,10 @@ "messageformat": "Close", "description": "Axo Design System > Dialog Component > Close Button > Generic accessibility label" }, + "icu:AxoPasswordField.Reveal": { + "messageformat": "Show Password", + "description": "Axo Design System > Password Field Component > Reveal Button > Generic accessibility label" + }, "icu:AxoTextField.Clear": { "messageformat": "Clear", "description": "Axo Design System > Text Field Component > Clear Button > Generic accessibility label" diff --git a/ts/axo/AxoTextField.dom.tsx b/ts/axo/AxoTextField.dom.tsx deleted file mode 100644 index 74ae742fb6..0000000000 --- a/ts/axo/AxoTextField.dom.tsx +++ /dev/null @@ -1,627 +0,0 @@ -// Copyright 2026 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only -import { memo, useCallback, useId, useMemo, useRef } from 'react'; -import type { FC, InputEvent, MouseEvent, ReactNode, RefObject } from 'react'; -import { mergeRefs } from '@react-aria/utils'; -import { AxoSymbol } from './AxoSymbol.dom.tsx'; -import { tw } from './tw.dom.tsx'; -import { assert } from './_internal/assert.std.tsx'; -import { utf8 } from './_internal/utf8.std.ts'; -import { - createStrictContext, - useStrictContext, -} from './_internal/StrictContext.dom.tsx'; -import { useAxoIntl } from './_internal/AxoIntl.dom.tsx'; -import { variants } from './_internal/variants.dom.tsx'; - -/** - * A single-line text input with optional icons, action buttons, and - * character/byte limiting. - * - * @example Anatomy - * ```tsx - * - * - * - * - * - * - * ``` - * @see {@link https://w3c.github.io/aria/#textbox | `textbox` role - WAI-ARIA 1.3} - * @see {@link https://w3c.github.io/aria/#group | `group` role - WAI-ARIA 1.3} - */ -export namespace AxoTextField { - /** - * - * -------------------------------------------------------------------------- - */ - - /** @internal */ - type RootContextType = Readonly<{ - disabled?: boolean; - readOnly?: boolean; - }>; - - /** @internal */ - const RootContext = createStrictContext('AxoTextField.Root'); - - /** - * The preferred width of the text field. - * - * TODO(jamie): Get real sizes from design - * - * - `xs` – 200px - * - `sm` – 300px - * - `md` – 400px - * - `lg` – 500px - * - `xl` – 600px - * - `full` – stretches to fill the container (default) - * - * All sizes shrink to fit the container if it is narrower than the minimum. - */ - export type Width = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full'; - - export type RootProps = Readonly<{ - /** Leading icon displayed before the input. */ - symbol?: AxoSymbol.IconName; - /** Controls the width of the entire field. Defaults to `full`. */ - width?: Width; - /** Disables all inputs and actions within the field. */ - disabled?: boolean; - /** Makes all inputs within the field read-only. */ - readOnly?: boolean; - /** Should be `Input`, `Action`, and/or `Separator` elements. */ - children: ReactNode; - }>; - - /** - * Container for the text field. Provides shared `disabled`/`readOnly` state - * to child inputs and actions. - * - * @example Basic usage - * ```tsx - * - * - * - * ``` - * - * @example Segmented field with icon and action - * ```tsx - * - * - * - * - * - * - * ``` - */ - export const Root: FC = memo(props => { - const { disabled, readOnly } = props; - - const context = useMemo((): RootContextType => { - return { disabled, readOnly }; - }, [disabled, readOnly]); - - return ( - - - {props.symbol != null && } - {props.children} - - - ); - }); - - Root.displayName = 'AxoTextField.Root'; - - /** - * - * -------------------------------------------------------------------------- - */ - - const GroupWidthStyles = variants('AxoTextField.Width', { - xs: tw('w-[calc-size(fit-content,min(max(200px,size),100%))]'), - sm: tw('w-[calc-size(fit-content,min(max(300px,size),100%))]'), - md: tw('w-[calc-size(fit-content,min(max(400px,size),100%))]'), - lg: tw('w-[calc-size(fit-content,min(max(500px,size),100%))]'), - xl: tw('w-[calc-size(fit-content,min(max(600px,size),100%))]'), - full: tw('w-full'), - }); - - /** @internal */ - type GroupProps = Readonly<{ - width: Width; - children: ReactNode; - }>; - - /** @internal */ - const Group: FC = memo(props => { - return ( -
- {props.children} -
- ); - }); - - Group.displayName = 'AxoTextField.Group'; - - /** - * - * -------------------------------------------------------------------------- - */ - - /** - * How an `Input` sizes itself within the field group. - * - `fixed`: Takes up all remaining space (default). - * - `grow`: Expands with typed content, up to available space. - * - `fit`: Shrinks to fit typed content, useful for segmented fields. - */ - export type Sizing = 'fixed' | 'grow' | 'fit'; - - export type InputProps = Readonly<{ - /** Ref to the underlying `` element. */ - ref?: RefObject; - /** Provide your own id for the `` to target with a `