{"version":3,"sources":["../src/input/input.tsx"],"names":["forwardRef","Input","usePermissions","resolvePermissions","useAudit","evaluatePermission","useRef","CANONICAL_ACTIONS","jsx"],"mappings":"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","file":"input.cjs","sourcesContent":["/**\n * Input — headless proprietary primitive.\n *\n * Client component (consumes `PermissionContext` + `AuditContext` via\n * `useContext`). Wraps the native `<input>` with:\n *   - Permission gating via `can('edit', resource, attrs)`. The three\n *     modes collapse cleanly for form fields: `disabled` → native\n *     disabled, `readOnly` → native readOnly (visible, focus-reachable,\n *     non-mutating), `hidden` → returns null.\n *   - Canonical `input:change` audit emission on blur (not per-keystroke —\n *     that would drown the stream; blur is the semantic \"I'm done typing\"\n *     boundary). Also `input:blur` when a consumer needs the signal\n *     separately. `permission:denied` on blocked edits in `readOnly`.\n *   - `data-oshon-primitive=\"input\"` + `data-permission-state` styling hooks.\n *\n * Proprietary rather than Radix-wrapped because native `<input>` behavior\n * is narrow — label wiring (htmlFor), form association, constraint\n * validation, ARIA defaults all come free. See ADR-001 for the\n * \"proprietary vs. Radix\" rubric (same rubric applied to Button).\n */\n\n'use client';\n\nimport { forwardRef, useRef } from 'react';\nimport type {\n  FocusEventHandler,\n  ChangeEventHandler,\n  InputHTMLAttributes,\n  Ref,\n} from 'react';\nimport {\n  evaluatePermission,\n  resolvePermissions,\n  usePermissions,\n  useAudit,\n  type PermissionContext,\n} from '../context.js';\nimport { CANONICAL_ACTIONS } from '../actions.js';\n\ntype NativeInputProps = Omit<\n  InputHTMLAttributes<HTMLInputElement>,\n  'disabled' | 'readOnly' | 'aria-invalid'\n>;\n\nexport interface InputProps extends NativeInputProps {\n  /**\n   * Disable the input. Renders with the native `disabled` attribute so\n   * screen readers and keyboard users get consistent signal. No change /\n   * blur audit events fire while disabled.\n   */\n  disabled?: boolean;\n  /**\n   * Non-mutating but still interactive. Renders with native `readOnly`\n   * so the field is focus-reachable, copy-friendly, and announced as\n   * read-only by assistive tech. Change events are silently dropped.\n   */\n  readOnly?: boolean;\n  /**\n   * Marks the field as invalid for a11y. `true` → `aria-invalid=\"true\"`.\n   * The visual layer surfaces the error styling; primitive only ensures\n   * correct ARIA.\n   */\n  invalid?: boolean;\n  /**\n   * Per-instance permission override. Merges over the ambient\n   * `PermissionContext`. Example: `permissions={{ mode: 'hidden' }}`\n   * switches this one instance to render-as-null when denied.\n   */\n  permissions?: Partial<PermissionContext>;\n  /**\n   * Resource name passed to `permissions.can('edit', resource, attrs)`.\n   * Default `'input'`. Consumers override for specific semantics, e.g.\n   * `resource=\"field:ssn\"` for a sensitive data field.\n   */\n  resource?: string;\n  /**\n   * Attribute bag forwarded to `permissions.can(..., attrs)` for\n   * attribute-based access control. Primitives never invent values here\n   * — the consumer supplies them.\n   */\n  permissionAttrs?: Record<string, unknown>;\n}\n\n/**\n * Headless input. Accessible `<input>` with:\n *   - `disabled` / `readOnly` / `aria-invalid` / `aria-disabled`\n *     synchronised\n *   - Permission gating via `can('edit', resource, attrs)`:\n *       - `mode='disabled'` (default) — renders native `disabled`\n *       - `mode='readOnly'` — renders native `readOnly` (visible,\n *         focus-reachable, non-mutating)\n *       - `mode='hidden'` — returns null\n *   - Canonical `input:change` + `input:blur` audit on blur (granted);\n *     `permission:denied` when the user attempts to mutate a\n *     readOnly-gated field\n *   - `data-oshon-primitive=\"input\"` styling hook\n *   - `data-permission-state=\"denied\"` styling hook under any deny mode\n *     that keeps the affordance visible\n *   - No visual styling — consumers supply their own className / styles.\n *\n * Keyboard: native browser behavior — Tab focuses, typing mutates.\n */\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n  function Input(\n    {\n      disabled = false,\n      readOnly = false,\n      invalid = false,\n      permissions,\n      resource = 'input',\n      permissionAttrs,\n      onChange,\n      onBlur,\n      value,\n      defaultValue,\n      ...rest\n    }: InputProps,\n    ref: Ref<HTMLInputElement>,\n  ) {\n    const contextPermissions = usePermissions();\n    const effective = resolvePermissions(permissions, contextPermissions);\n    const mode = effective.mode ?? 'disabled';\n    const emit = useAudit();\n\n    const { granted, denyReason } = evaluatePermission(\n      effective,\n      'edit',\n      resource,\n      permissionAttrs,\n    );\n\n    // Track whether the current value differs from the value at focus so\n    // the blur emit only fires `input:change` when the user actually\n    // changed something. Consumers who want per-keystroke telemetry layer\n    // that on top via `onChange` — primitive stream stays quiet.\n    const focusValueRef = useRef<string | null>(null);\n    const changedSinceFocusRef = useRef(false);\n\n    if (!granted && mode === 'hidden') return null;\n\n    const permissionBlocks = !granted && mode !== 'readOnly';\n    const isDisabled = disabled || permissionBlocks;\n    const isReadOnly = readOnly || (!granted && mode === 'readOnly');\n\n    const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {\n      if (disabled) return;\n\n      if (!granted && mode === 'readOnly') {\n        // User attempted to mutate a permission-gated readOnly field.\n        // Record the denial once per keystroke attempt — governance can\n        // aggregate these into \"user tried to edit X N times\" signals.\n        emit({\n          component: 'input',\n          action: CANONICAL_ACTIONS.PERMISSION_DENIED,\n          permissionResult: 'denied',\n          ...(denyReason ? { denyReason } : {}),\n          details: { attemptedAction: 'edit', resource },\n        });\n        // Don't forward — a readOnly field must not let consumer state\n        // drift into an edit it rejected.\n        return;\n      }\n\n      if (readOnly) {\n        // Locally readOnly — silent drop, no audit (the consumer\n        // declared the field read-only on purpose).\n        return;\n      }\n\n      changedSinceFocusRef.current = true;\n      onChange?.(event);\n    };\n\n    const handleFocus: FocusEventHandler<HTMLInputElement> = (event) => {\n      focusValueRef.current = event.currentTarget.value;\n      changedSinceFocusRef.current = false;\n      rest.onFocus?.(event);\n    };\n\n    const handleBlur: FocusEventHandler<HTMLInputElement> = (event) => {\n      // Blur fires regardless of permission state — disabled fields\n      // can't be focused, so a blur here implies the field was\n      // interactable. Still audit even if the user didn't change\n      // anything (consumers can filter on `details.changed`).\n      if (!disabled && granted && !readOnly) {\n        emit({\n          component: 'input',\n          action: CANONICAL_ACTIONS.INPUT_BLUR,\n          permissionResult: 'granted',\n          details: { changed: changedSinceFocusRef.current },\n        });\n        if (changedSinceFocusRef.current) {\n          emit({\n            component: 'input',\n            action: CANONICAL_ACTIONS.INPUT_CHANGE,\n            permissionResult: 'granted',\n          });\n        }\n      }\n      onBlur?.(event);\n    };\n\n    const permissionDataState =\n      !granted && mode !== 'hidden' ? 'denied' : undefined;\n\n    const resolvedTitle =\n      rest.title ?? (permissionDataState && denyReason ? denyReason : undefined);\n\n    return (\n      <input\n        {...rest}\n        ref={ref}\n        value={value}\n        defaultValue={defaultValue}\n        disabled={isDisabled}\n        readOnly={isReadOnly}\n        aria-disabled={isDisabled || undefined}\n        aria-readonly={isReadOnly || undefined}\n        aria-invalid={invalid || undefined}\n        data-oshon-primitive=\"input\"\n        data-permission-state={permissionDataState}\n        title={resolvedTitle}\n        onChange={handleChange}\n        onFocus={handleFocus}\n        onBlur={handleBlur}\n      />\n    );\n  },\n);\n"]}