IS-11008 HAAPI FE Lib documentation - #274
Conversation
There was a problem hiding this comment.
Pull request overview
This PR moves HAAPI React SDK documentation ownership into the SDK package by adding a docs source tree and runnable, typechecked examples, while updating TSDoc on public exports so the Curity docs site can generate API reference and playground pages directly from this repository.
Changes:
- Added
docs/sections/source tree +_harness/playground infrastructure and many co-located runnable example apps. - Expanded/standardized TSDoc across exported components/hooks (including
{@see_example ...}markers and@docsIgnoretags). - Updated tooling and repo entrypoints (TS/ESLint/Prettier/CI workspace naming, app readme links, launcher page link).
Reviewed changes
Copilot reviewed 98 out of 100 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/haapi-react-sdk/tsconfig.json | Include docs/ in typecheck and map package-name imports for examples. |
| src/haapi-react-sdk/README.md | New package-root README used as Overview docs source + contributor guide for docs conventions. |
| src/haapi-react-sdk/haapi-stepper/ui/messages/HaapiStepperMessageUI.tsx | Add API doc + example marker for single-message rendering. |
| src/haapi-react-sdk/haapi-stepper/ui/messages/HaapiStepperMessagesUI.tsx | Normalize doc headings + add example marker. |
| src/haapi-react-sdk/haapi-stepper/ui/links/HaapiStepperQrCodeLinkDialog.tsx | Mark as @docsIgnore. |
| src/haapi-react-sdk/haapi-stepper/ui/links/HaapiStepperLinkUI.tsx | Add API doc + example marker for single-link rendering. |
| src/haapi-react-sdk/haapi-stepper/ui/links/HaapiStepperLinksUI.tsx | Fix example snippet + normalize doc headings + add example marker. |
| src/haapi-react-sdk/haapi-stepper/ui/actions/HaapiStepperActionsUI.tsx | Add API doc + example marker for actions collection rendering. |
| src/haapi-react-sdk/haapi-stepper/README.md | Remove legacy README content (docs now sourced elsewhere). |
| src/haapi-react-sdk/haapi-stepper/feature/viewnames/HaapiStepperBankIdQrCodeAccessibilityMessages.tsx | Add @docsIgnore. |
| src/haapi-react-sdk/haapi-stepper/feature/viewnames/HaapiStepperBankIdPollingProgressUI.tsx | Add @docsIgnore. |
| src/haapi-react-sdk/haapi-stepper/feature/steps/HaapiStepperStepUI.tsx | Rewrite/structure TSDoc + add multiple example markers. |
| src/haapi-react-sdk/haapi-stepper/feature/stepper/HaapiStepperHook.ts | Update hook TSDoc + add example marker. |
| src/haapi-react-sdk/haapi-stepper/feature/stepper/HaapiStepperErrorNotifier.tsx | Add component TSDoc + example marker. |
| src/haapi-react-sdk/haapi-stepper/feature/stepper/HaapiStepperContext.tsx | Mark as @docsIgnore. |
| src/haapi-react-sdk/haapi-stepper/feature/stepper/HaapiStepper.tsx | Restructure provider TSDoc + add multiple example markers + update wording. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/selector/HaapiStepperSelectorUI.tsx | Normalize heading + add example marker. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/form/HaapiStepperFormValidationErrorInputWrapper.tsx | Add component TSDoc + example marker. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/form/HaapiStepperFormUI.tsx | Restructure docs + add example markers and references. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/form/HaapiStepperFormSubmitButton.tsx | Add component TSDoc + example marker. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/form/HaapiStepperFormHook.ts | Add hook usage docs + example marker. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/form/HaapiStepperFormContext.ts | Mark internal context/hook as @docsIgnore. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/form/fields/HaapiStepperTextFormFieldUI.tsx | Add component docs + example marker. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/form/fields/HaapiStepperSelectFormFieldUI.tsx | Add component docs + example marker. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/form/fields/HaapiStepperPasswordFormFieldUI.tsx | Add component docs + example marker. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/form/fields/HaapiStepperFormFieldUI.tsx | Add component docs + example marker. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/form/fields/HaapiStepperCheckboxFormFieldUI.tsx | Add component docs + example marker. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/client-operation/operations/webauthn/HaapiStepperWebAuthnRegistrationAttachmentCard.tsx | Add @docsIgnore. |
| src/haapi-react-sdk/haapi-stepper/feature/actions/client-operation/HaapiStepperClientOperationUI.tsx | Normalize heading + add example marker. |
| src/haapi-react-sdk/haapi-stepper/data-access/useHaapiFetch.ts | Add hook docs + usage snippet. |
| src/haapi-react-sdk/eslint.config.js | Relax selected rules for docs/** to fit teaching/example patterns. |
| src/haapi-react-sdk/docs/sections/README.md | Docs root section header/intro for generated menu. |
| src/haapi-react-sdk/docs/sections/00-overview/README.md | Overview section metadata; examples live here. |
| src/haapi-react-sdk/docs/sections/00-overview/HaapiStepperPreviewHaapiReactSDKPlaygroundExample.tsx | Step catalog playground example. |
| src/haapi-react-sdk/docs/sections/00-overview/DefaultRenderingHaapiReactSDKPlaygroundExample.tsx | Default HaapiStepperStepUI rendering example. |
| src/haapi-react-sdk/docs/sections/00-overview/StepBuildingBlocksHaapiReactSDKPlaygroundExample.tsx | Building-block composition example. |
| src/haapi-react-sdk/docs/sections/00-overview/StylesButtonCustomizationHaapiReactSDKPlaygroundExample.tsx | CSS-only customization example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/README.md | API reference section index (ordered exports list). |
| src/haapi-react-sdk/docs/sections/01-api-reference/UseHaapiStepperHookHaapiReactSDKPlaygroundExample.tsx | useHaapiStepper example app. |
| src/haapi-react-sdk/docs/sections/01-api-reference/LoadingDataRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Loading data interceptor example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/LoadingRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Loading UI interceptor example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/LoadingBehaviorRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Loading side-effect example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/StepDataRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Step data rewrite example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/StepRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Full step UI replacement example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/StepBehaviorRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Wrap nextStep behavior example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/ConditionalCustomizationHaapiReactSDKPlaygroundExample.tsx | Conditional customization example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/BuildingBlocksUICompositionHaapiReactSDKPlaygroundExample.tsx | Manual building-block step composition example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/FullCustomizationUICompositionHaapiReactSDKPlaygroundExample.tsx | Full custom UI composition with a component library example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/README.md | UI components section text + embedded runnable example reference. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/ActionsUiUsageHaapiReactSDKPlaygroundExample.tsx | Actions building-block usage example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/SelectorUiUsageHaapiReactSDKPlaygroundExample.tsx | Selector building-block usage example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/ClientOperationUiUsageHaapiReactSDKPlaygroundExample.tsx | Client-operation building-block usage example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/LinkUiUsageHaapiReactSDKPlaygroundExample.tsx | Links collection usage example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/SingleLinkUiUsageHaapiReactSDKPlaygroundExample.tsx | Single link usage example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/MessagesRenderingHaapiReactSDKPlaygroundExample.tsx | Messages collection usage example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/SingleMessageUiUsageHaapiReactSDKPlaygroundExample.tsx | Single message usage example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/ErrorNotifierHaapiReactSDKPlaygroundExample.tsx | Error notifier example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/FormValidationErrorWrapperHaapiReactSDKPlaygroundExample.tsx | Field validation wrapper example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/UiComponentsCompositionUsageHaapiReactSDKPlaygroundExample.tsx | Mixed building-block composition example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/01-form-ui/README.md | Form UI subsection index. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/01-form-ui/FormUICompositionHaapiReactSDKPlaygroundExample.tsx | Form composition example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/01-form-ui/FormFieldRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Field interceptor example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/01-form-ui/FormStateHookUsageHaapiReactSDKPlaygroundExample.tsx | useHaapiStepperFormState example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/01-form-ui/FormSubmitBehaviorHaapiReactSDKPlaygroundExample.tsx | Submission behavior wrapping example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/01-form-ui/SubmitButtonCustomizationHaapiReactSDKPlaygroundExample.tsx | Submit button customization example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/01-form-ui/TextFieldRenderingHaapiReactSDKPlaygroundExample.tsx | Direct text field placement example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/01-form-ui/PasswordFieldRenderingHaapiReactSDKPlaygroundExample.tsx | Direct password field placement example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/01-form-ui/SelectFieldRenderingHaapiReactSDKPlaygroundExample.tsx | Direct select field placement example. |
| src/haapi-react-sdk/docs/sections/01-api-reference/01-ui-components/01-form-ui/CheckboxFieldRenderingHaapiReactSDKPlaygroundExample.tsx | Direct checkbox field placement example. |
| src/haapi-react-sdk/docs/sections/02-examples/README.md | Examples section index. |
| src/haapi-react-sdk/docs/sections/02-examples/01-render-interceptors/README.md | Render interceptor examples section index. |
| src/haapi-react-sdk/docs/sections/02-examples/01-render-interceptors/MessageRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Message interceptor example. |
| src/haapi-react-sdk/docs/sections/02-examples/01-render-interceptors/LinkRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Link interceptor example. |
| src/haapi-react-sdk/docs/sections/02-examples/01-render-interceptors/ActionsRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Actions wrapper interceptor example. |
| src/haapi-react-sdk/docs/sections/02-examples/01-render-interceptors/ClientOperationRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Client-operation interceptor example. |
| src/haapi-react-sdk/docs/sections/02-examples/01-render-interceptors/SelectorReorderRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Selector option reorder example. |
| src/haapi-react-sdk/docs/sections/02-examples/01-render-interceptors/SelectorRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Selector UI replacement example. |
| src/haapi-react-sdk/docs/sections/02-examples/01-render-interceptors/01-error-positioning/README.md | Error positioning examples section index. |
| src/haapi-react-sdk/docs/sections/02-examples/01-render-interceptors/01-error-positioning/ErrorInWellRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Error restyle-in-place example. |
| src/haapi-react-sdk/docs/sections/02-examples/01-render-interceptors/01-error-positioning/ErrorAboveStepRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Error moved above step example. |
| src/haapi-react-sdk/docs/sections/02-examples/01-render-interceptors/01-error-positioning/ErrorAboveFormRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Error moved inside form example. |
| src/haapi-react-sdk/docs/sections/02-examples/02-ui-composition/README.md | UI composition examples section index. |
| src/haapi-react-sdk/docs/sections/02-examples/02-ui-composition/ComposedLayoutRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | Mixed interceptor + composition layout example. |
| src/haapi-react-sdk/docs/sections/02-examples/03-advanced/README.md | Advanced examples section index. |
| src/haapi-react-sdk/docs/sections/02-examples/03-advanced/CaptchaRenderInterceptorHaapiReactSDKPlaygroundExample.tsx | reCAPTCHA-gated login form interceptor example. |
| src/haapi-react-sdk/docs/sections/02-examples/03-advanced/TabbedAuthenticatorUICompositionHaapiReactSDKPlaygroundExample.tsx | Tabbed authenticator selector composition example. |
| src/haapi-react-sdk/docs/_harness/third-party.d.ts | Ambient stubs for doc-only third-party imports. |
| src/haapi-react-sdk/docs/_harness/ExamplePreviewer.tsx | Preview chrome + served-mode window.__CONFIG__ injection. |
| src/haapi-react-sdk/docs/_harness/StepSelect.tsx | Step selector UI for previewer. |
| src/haapi-react-sdk/docs/_harness/StepDataDetails.tsx | Collapsible HAAPI step JSON viewer. |
| src/haapi-react-sdk/docs/_harness/config.ts | Mock HAAPI config + bootstrap generation helper. |
| src/haapi-react-sdk/docs/_harness/AutoSubmitForm.tsx | Auto-submit helper for error-state examples. |
| src/haapi-react-sdk/.prettierignore | Exclude docs/ from this workspace’s prettier check. |
| src/haapi-react-app/README.md | Link app docs to published SDK docs; update install/run guidance. |
| src/haapi-react-app/package.json | Add previewer:serve script. |
| package.json | Point start:haapi-react-app to previewer serve command. |
| package-lock.json | Lockfile updates from dependency refresh. |
| index.html | Add documentation link on the launcher page. |
| .github/workflows/lwa-github-ci-workflow.yml | Run SDK checks via workspace name @curity/haapi-react-sdk. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…arness. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… site. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ids Chrome's breach warning); note example CI coverage in the README. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
b1debb5 to
33a2d4c
Compare
vahag-curity
left a comment
There was a problem hiding this comment.
Reviewed the diff, read the ticket (IS-11008) and the whole comment thread, and tested locally: checked out the branch, ran ./gradlew :docs:previewProdDocs against the companion IDSVR generator branch, and browsed the generated site at localhost:4322/developer-guide/haapi-sdks/web-sdk.
Code review: every change under haapi-stepper/ (excluding docs/) is TSDoc-only — confirmed by reading the full diff, including the two large HaapiStepper.tsx/HaapiStepperStepUI.tsx hunks. Sampled 13 of the 44 new playground examples against the real SDK exports/types — no invented APIs, no stale props, no copy-paste bugs.
Comment thread: all 7 Copilot findings and the reCAPTCHA-key question are verified actually resolved in this HEAD (checked the real types/files, not just the thread's replies) — HaapiStepperAPI/HaapiStepperBootstrapConfig do expose config/theme now, the README casing and rel=noopener fixes are in, and the reCAPTCHA site key is Google's documented public test key.
Live testing: the generated site's structure matches the SDK README's convention exactly, and the Tabbed Authenticator example — flagged below as having a smoke-test coverage gap — renders correctly in the real browser (real antd loads via CDN in the sandbox), so that gap is CI-only, not a functional bug.
Two minor, non-blocking follow-ups left as comments below. Approving — nothing here blocks merge.
| Text: stub, | ||
| Paragraph: stub, | ||
| }); | ||
| export const List = Object.assign(({ children }: StubProps): ReactNode => children ?? null, { Item: stub }); |
There was a problem hiding this comment.
Minor test-coverage gap, not a functional bug (verified live): Tabs/Select/List here only render children, never items/onChange/renderItem. So DocsExamples.spec.tsx's smoke render never actually mounts the nested HaapiStepperStepUI logic inside TabbedAuthenticatorUICompositionHaapiReactSDKPlaygroundExample.tsx (where most of that example's bespoke logic lives) — same for Select's onChange and List's renderItem in a couple of the other advanced examples. I confirmed the real published example renders fine in the browser (real antd loads via CDN in the sandboxed playground), so this is purely a CI blind spot: a runtime bug inside one of those render-prop bodies would currently pass CI silently. Might be worth a small follow-up (e.g. have the stub also invoke items/renderItem where present) — not blocking this PR.
| README.md | ||
|
|
||
| # The docs are their own workspace with its own prettier-check (run via `-w src/haapi-react-sdk`). | ||
| docs |
There was a problem hiding this comment.
The comment says docs is "their own workspace with its own prettier-check (run via -w src/haapi-react-sdk)" — but -w src/haapi-react-sdk is this exact workspace; there's no separate docs workspace/prettier-check anywhere in CI. As a result docs/ is silently excluded from the only formatting check that exists, and at least one file (docs/sections/01-api-reference/01-ui-components/README.md) is already prettier-non-compliant. Since these files are published verbatim to the docs site, worth either dropping this ignore line or fixing the comment + wiring an actual check — not blocking, just flagging so it doesn't drift further.
luisgoncalves
left a comment
There was a problem hiding this comment.
I'm approving this part because the content here looks nice. Added more comments on the product docs counterpart.
| <small class="card-url">http://localhost:5174/</small> | ||
| <div class="documentation"> | ||
| <a | ||
| href="https://curity.io/docs/identity-server/developer-guide/haapi-sdks/web-sdk" |
There was a problem hiding this comment.
Hard-coding these links is always a bit tricky for maintenance, but I see how it's useful (and they probabyl need to be stable for SEO purposes et al, anyway). So, I suggest adding docs lnks to the other two cards as well, pointing to their relevant sections in product docs.
Also, I think the button is way too big. Maybe a simple link is enough? And saying "Read documentation" is probably enough as well - no need to duplicate part of the card title.
|
|
||
| <!-- docs:skip --> | ||
|
|
||
| ## Documentation |
There was a problem hiding this comment.
This is more dev/editor instructions, while the rest is public docs (also shown by "docs skip" above).
I suggest moving this section to a README inside the ./docs folder. Maybe just keep the "read the docs online" link here.
But the section content is nice 👍
| > 📖 **[Read the docs online](https://curity.io/docs/identity-server/developer-guide/haapi-sdks/web-sdk)** | ||
| > (Curity Docs → Developer Guide → HAAPI SDKs → Web SDK). | ||
| > The generator lives in the `identity-server` repo, at `docs/haapi-react-sdk-docgen` — its README | ||
| > explains how it works and how to preview the site locally. |
There was a problem hiding this comment.
Seems like too many details to be public, specially in the main README. I suggest just keeping a more generic note like "docs are generated as part of the Identity Server product docs based on the files in this package" - after moving this section to its own README.
| </HaapiStepper> | ||
| ``` | ||
|
|
||
| [Read more](/api-reference/stepper) |
There was a problem hiding this comment.
What's the convention for these links? If I got it right, this links to one of the generated pages for the section's exports, but the convention is not documented here.
Also. It's a bit weird that these don't work from the README. Would it be possible to link to the actual file, and then on the docs generation link to the generated docs file instead, if it matches one of the exports? I guess this would prevent direct links to these files, so not ideal either :/
| - the number is its position | ||
| - the name is its title and URL (readers never see the prefix) | ||
| - its `README.md` declares its description and the **ordered** list of the library's exports documented in | ||
| the section, as a plain numbered list (page order = list order; child folders follow, by prefix). |
There was a problem hiding this comment.
I think having the list of documented exports in the README is confusing and error prone. Suggested a different approach in the "docs generator" PR.
| ); | ||
| } | ||
| ``` | ||
| {@see_example ./docs/sections/01-api-reference/01-ui-components/UiComponentsCompositionUsageHaapiReactSDKPlaygroundExample.tsx} |
There was a problem hiding this comment.
This doesn't work in MD. Should it be a regular link to examples, which is then converted by the docs generator?
| * <HaapiComponentExample /> | ||
| * </HaapiStepper> | ||
| * ``` | ||
| * {@see_example ./docs/sections/01-api-reference/FullCustomizationUICompositionHaapiReactSDKPlaygroundExample.tsx} |
There was a problem hiding this comment.
I'm wondering if we should keep this big examples above. It makes the TSDoc a bit hard to read on the IDE and perhaps it's too much detail?
Maybe for these more complex examples we could just have a list with example links.
| 1. Create the file in the folder of the section that will show it: `docs/sections/00-overview/` (embedded on an | ||
| Overview page), `docs/sections/01-api-reference/` (embedded on an API Reference page), or the menu-group folder | ||
| (e.g. `docs/sections/02-examples/01-render-interceptors/`) for its own page in the Examples menu. | ||
| 2. Name it ending in `HaapiReactSDKPlaygroundExample` — for example |
There was a problem hiding this comment.
This suffix is very verbose. If the examples lookup is always contained to docs, I thing ending with Example could be enough, no?
| <small class="card-url">http://localhost:5174/</small> | ||
| <div class="documentation"> | ||
| <a | ||
| href="https://curity.io/docs/identity-server/developer-guide/haapi-sdks/web-sdk" |
There was a problem hiding this comment.
please use trailing slash on this link
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Supersedes #226 — same goal, final architecture, without the 30-commit build-then-pivot history.
What this PR does
Makes the HAAPI React SDK package the single source of truth for its documentation on the Curity docs site (Developer Guide → HAAPI SDKs → Web SDK). Everything the site shows is authored here and generated from it:
src/haapi-react-app/README.mdand speciallysrc/haapi-react-sdk/README.mdexplain how the docs workgit checkout feature/dev/IS-11008-haapi-react-sdk-docs./gradlew :docs:previewProdDocsThe generator itself lives in the
identity-serverrepo (docs/haapi-react-sdk-docgen); this PR contains only the SDK-side sources plus small tooling touches.