···88import { BaseLayout } from '#web/layouts/base.tsx';
99import { getAppContext } from '#web/middlewares/app-context.ts';
1010import { getSession } from '#web/middlewares/session.ts';
1111-import Button from '#web/primitives/button.tsx';
1212-import DialogActions from '#web/primitives/dialog-actions.tsx';
1313-import DialogBody from '#web/primitives/dialog-body.tsx';
1414-import DialogContent from '#web/primitives/dialog-content.tsx';
1515-import DialogTitle from '#web/primitives/dialog-title.tsx';
1616-import Field from '#web/primitives/field.tsx';
1717-import Input from '#web/primitives/input.tsx';
1111+import { Button, Dialog, Field, Input } from '#web/primitives/index.ts';
1812import { routes } from '#web/routes.ts';
19132020-import {
2121- completeWebAuthnForm,
2222- initiateWebAuthnRegistration,
2323- removeWebAuthnForm,
2424-} from './webauthn/lib/forms';
1414+import { completeWebAuthnForm, initiateWebAuthnRegistration, removeWebAuthnForm } from './webauthn/lib/forms';
25152616export default {
2717 middleware: [],
···5040 const existingChallenge = accountManager.getWebAuthnChallenge(token);
5141 if (existingChallenge) {
5242 // regenerate options with the same challenge
5353- const state = await initiateWebAuthnRegistration(
5454- session.did,
5555- account.handle ?? session.did,
5656- );
4343+ const state = await initiateWebAuthnRegistration(session.did, account.handle ?? session.did);
5744 // delete old challenge and use new one
5845 accountManager.deleteWebAuthnChallenge(token);
5946 token = state.token;
···63506451 if (!options) {
6552 // generate new registration
6666- const state = await initiateWebAuthnRegistration(
6767- session.did,
6868- account.handle ?? session.did,
6969- );
5353+ const state = await initiateWebAuthnRegistration(session.did, account.handle ?? session.did);
7054 token = state.token;
7155 options = state.options;
7256 }
···8266 <div class="flex flex-1 items-center justify-center p-4">
8367 <div class="w-full max-w-120 rounded-xl bg-neutral-background-1 shadow-64">
8468 <form {...completeWebAuthnForm} class="contents">
8585- <DialogBody>
8686- <DialogTitle>Set up security key</DialogTitle>
6969+ <Dialog.Body>
7070+ <Dialog.Title>Set up security key</Dialog.Title>
87718888- <DialogContent class="flex flex-col gap-4">
7272+ <Dialog.Content class="flex flex-col gap-4">
8973 <p class="text-base-300">
9074 Insert your security key and follow your browser's prompts to register it.
9175 </p>
···125109 {generalError.message}
126110 </p>
127111 )}
128128- </DialogContent>
112112+ </Dialog.Content>
129113130130- <DialogActions>
114114+ <Dialog.Actions>
131115 <Button type="button" href={routes.account.security.overview.href()}>
132116 Cancel
133117 </Button>
134118135135- <Button
136136- type="submit"
137137- variant="primary"
138138- disabled
139139- data-target="webauthn-register.submit"
140140- >
119119+ <Button type="submit" variant="primary" disabled data-target="webauthn-register.submit">
141120 Save
142121 </Button>
143143- </DialogActions>
144144- </DialogBody>
122122+ </Dialog.Actions>
123123+ </Dialog.Body>
145124 </form>
146125 </div>
147126 </div>
···183162 <form {...removeWebAuthnForm} class="contents">
184163 <input {...fields.id.as('hidden', params.id)} />
185164186186- <DialogBody>
187187- <DialogTitle>Remove this security key?</DialogTitle>
165165+ <Dialog.Body>
166166+ <Dialog.Title>Remove this security key?</Dialog.Title>
188167189189- <DialogContent>
168168+ <Dialog.Content>
190169 <p class="text-base-300">
191170 You'll no longer be able to use "{credential.name}" to sign in.
192171 </p>
···196175 {error.message}
197176 </p>
198177 )}
199199- </DialogContent>
178178+ </Dialog.Content>
200179201201- <DialogActions>
180180+ <Dialog.Actions>
202181 <Button type="button" href={routes.account.security.overview.href()}>
203182 Cancel
204183 </Button>
···206185 <Button type="submit" variant="primary">
207186 Remove
208187 </Button>
209209- </DialogActions>
210210- </DialogBody>
188188+ </Dialog.Actions>
189189+ </Dialog.Body>
211190 </form>
212191 </div>
213192 </div>
+9-12
packages/danaus/src/web/controllers/admin.tsx
···22import { forms } from '@oomfware/forms';
33import { render } from '@oomfware/jsx';
4455-import StatCard from '../admin/components/stat-card.tsx';
66-import { createAccountForm } from '../admin/forms.ts';
77-import MagnifyingGlassOutlined from '../icons/central/magnifying-glass-outlined.tsx';
88-import PlusLargeOutlined from '../icons/central/plus-large-outlined.tsx';
99-import { AdminLayout } from '../layouts/admin.tsx';
1010-import { getAppContext } from '../middlewares/app-context.ts';
1111-import { requireAdmin } from '../middlewares/basic-auth.ts';
1212-import Button from '../primitives/button.tsx';
1313-import Field from '../primitives/field.tsx';
1414-import Input from '../primitives/input.tsx';
1515-import Select from '../primitives/select.tsx';
1616-import { routes } from '../routes.ts';
55+import StatCard from '#web/admin/components/stat-card.tsx';
66+import { createAccountForm } from '#web/admin/forms.ts';
77+import MagnifyingGlassOutlined from '#web/icons/central/magnifying-glass-outlined.tsx';
88+import PlusLargeOutlined from '#web/icons/central/plus-large-outlined.tsx';
99+import { AdminLayout } from '#web/layouts/admin.tsx';
1010+import { getAppContext } from '#web/middlewares/app-context.ts';
1111+import { requireAdmin } from '#web/middlewares/basic-auth.ts';
1212+import { Button, Field, Input, Select } from '#web/primitives/index.ts';
1313+import { routes } from '#web/routes.ts';
17141815export default {
1916 middleware: [requireAdmin(), forms({ createAccountForm })],
+1-4
packages/danaus/src/web/controllers/login.tsx
···33import { render } from '@oomfware/jsx';
4455import { BaseLayout } from '#web/layouts/base.tsx';
66-import Button from '#web/primitives/button.tsx';
77-import Checkbox from '#web/primitives/checkbox.tsx';
88-import Field from '#web/primitives/field.tsx';
99-import Input from '#web/primitives/input.tsx';
66+import { Button, Checkbox, Field, Input } from '#web/primitives/index.ts';
107import { routes } from '#web/routes.ts';
118129import { loginForm } from './login/lib/forms.ts';
+4-4
packages/danaus/src/web/controllers/oauth.tsx
···11import type { Controller } from '@oomfware/fetch-router';
22import { render } from '@oomfware/jsx';
3344-import { BaseLayout } from '../layouts/base.tsx';
55-import { requireSession } from '../middlewares/session.ts';
66-import Button from '../primitives/button.tsx';
77-import { routes } from '../routes.ts';
44+import { BaseLayout } from '#web/layouts/base.tsx';
55+import { requireSession } from '#web/middlewares/session.ts';
66+import { Button } from '#web/primitives/index.ts';
77+import { routes } from '#web/routes.ts';
8899export default {
1010 authorize: {
···11import { cloneElement, type JSXElement } from '@oomfware/jsx';
2233-import { useDialogContext } from './utils/dialog-context.tsx';
33+import { useDialogContext } from './utils/context.tsx';
4455export interface DialogTriggerProps {
66 children: JSXElement;
+16-27
packages/danaus/src/web/primitives/dialog.tsx
···11-import type { JSXNode } from '@oomfware/jsx';
22-33-import { useId } from '../components/id.tsx';
44-55-import { DialogContext, type DialogContextValue } from './utils/dialog-context.tsx';
11+export { default as Root } from './dialog/root.tsx';
22+export { default as Trigger } from './dialog/trigger.tsx';
33+export { default as Close } from './dialog/close.tsx';
44+export { default as Actions } from './dialog/actions.tsx';
55+export { default as Content } from './dialog/content.tsx';
66+export { default as Title } from './dialog/title.tsx';
77+export { default as Surface } from './dialog/surface.tsx';
88+export { default as Body } from './dialog/body.tsx';
6977-export interface DialogProps {
88- id?: string;
99- children?: JSXNode;
1010-}
1111-1212-/**
1313- * dialog root component wrapping native `<dialog>` element
1414- * @param props.id unique identifier for invoker command targeting
1515- * @param props.class additional CSS classes
1616- */
1717-const Dialog = (props: DialogProps) => {
1818- const { id = useId(), children } = props;
1919-2020- const contextValue: DialogContextValue = {
2121- dialogId: id,
2222- titleId: useId(),
2323- };
2424-2525- return <DialogContext.Provider value={contextValue}>{children}</DialogContext.Provider>;
2626-};
2727-2828-export default Dialog;
1010+export type { DialogProps } from './dialog/root.tsx';
1111+export type { DialogTriggerProps } from './dialog/trigger.tsx';
1212+export type { DialogCloseProps } from './dialog/close.tsx';
1313+export type { DialogActionsProps } from './dialog/actions.tsx';
1414+export type { DialogContentProps } from './dialog/content.tsx';
1515+export type { DialogTitleProps } from './dialog/title.tsx';
1616+export type { DialogSurfaceProps } from './dialog/surface.tsx';
1717+export type { DialogBodyProps } from './dialog/body.tsx';
···11+// namespace exports for compound components
22+export * as Dialog from './dialog.tsx';
33+export * as Accordion from './accordion.tsx';
44+export * as MessageBar from './message-bar.tsx';
55+export * as Menu from './menu.tsx';
66+77+// direct exports for simple components
88+export { default as Button } from './button.tsx';
99+export { default as Checkbox } from './checkbox.tsx';
1010+export { default as Field } from './field.tsx';
1111+export { default as Input } from './input.tsx';
1212+export { default as Label } from './label.tsx';
1313+export { default as Radio } from './radio.tsx';
1414+export { default as RadioGroup } from './radio-group.tsx';
1515+export { default as Select } from './select.tsx';
1616+1717+// type re-exports
1818+export type { ButtonProps } from './button.tsx';
1919+export type { CheckboxProps } from './checkbox.tsx';
2020+export type { FieldProps } from './field.tsx';
2121+export type { InputProps } from './input.tsx';
2222+export type { LabelProps } from './label.tsx';
2323+export type { RadioProps } from './radio.tsx';
2424+export type { RadioGroupProps } from './radio-group.tsx';
2525+export type { SelectProps } from './select.tsx';