@c9up/nebula 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +256 -0
- package/dist/adapters/css.d.ts +33 -0
- package/dist/adapters/css.js +67 -0
- package/dist/adapters/index.d.ts +16 -0
- package/dist/adapters/index.js +27 -0
- package/dist/adapters/tailwind.d.ts +25 -0
- package/dist/adapters/tailwind.js +122 -0
- package/dist/adapters/types.d.ts +49 -0
- package/dist/adapters/types.js +21 -0
- package/dist/adapters/unocss.d.ts +17 -0
- package/dist/adapters/unocss.js +107 -0
- package/dist/atoms/AspectRatio.d.ts +17 -0
- package/dist/atoms/AspectRatio.js +19 -0
- package/dist/atoms/Avatar.d.ts +23 -0
- package/dist/atoms/Avatar.js +46 -0
- package/dist/atoms/Badge.d.ts +25 -0
- package/dist/atoms/Badge.js +28 -0
- package/dist/atoms/Button.d.ts +58 -0
- package/dist/atoms/Button.js +67 -0
- package/dist/atoms/Checkbox.d.ts +41 -0
- package/dist/atoms/Checkbox.js +47 -0
- package/dist/atoms/Input.d.ts +36 -0
- package/dist/atoms/Input.js +50 -0
- package/dist/atoms/Kbd.d.ts +14 -0
- package/dist/atoms/Kbd.js +17 -0
- package/dist/atoms/Label.d.ts +24 -0
- package/dist/atoms/Label.js +26 -0
- package/dist/atoms/Marker.d.ts +42 -0
- package/dist/atoms/Marker.js +55 -0
- package/dist/atoms/NativeSelect.d.ts +43 -0
- package/dist/atoms/NativeSelect.js +81 -0
- package/dist/atoms/Progress.d.ts +21 -0
- package/dist/atoms/Progress.js +48 -0
- package/dist/atoms/ScrollArea.d.ts +28 -0
- package/dist/atoms/ScrollArea.js +37 -0
- package/dist/atoms/Separator.d.ts +16 -0
- package/dist/atoms/Separator.js +21 -0
- package/dist/atoms/Skeleton.d.ts +13 -0
- package/dist/atoms/Skeleton.js +18 -0
- package/dist/atoms/Slider.d.ts +30 -0
- package/dist/atoms/Slider.js +40 -0
- package/dist/atoms/Spinner.d.ts +17 -0
- package/dist/atoms/Spinner.js +20 -0
- package/dist/atoms/Switch.d.ts +24 -0
- package/dist/atoms/Switch.js +41 -0
- package/dist/atoms/Textarea.d.ts +28 -0
- package/dist/atoms/Textarea.js +36 -0
- package/dist/atoms/Toggle.d.ts +38 -0
- package/dist/atoms/Toggle.js +45 -0
- package/dist/atoms/index.d.ts +32 -0
- package/dist/atoms/index.js +32 -0
- package/dist/cli/add.d.ts +44 -0
- package/dist/cli/add.js +99 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.js +10 -0
- package/dist/cli/registry.d.ts +31 -0
- package/dist/cli/registry.js +83 -0
- package/dist/config.d.ts +81 -0
- package/dist/config.js +43 -0
- package/dist/configure.d.ts +34 -0
- package/dist/configure.js +85 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +41 -0
- package/dist/lib/children.d.ts +28 -0
- package/dist/lib/children.js +27 -0
- package/dist/lib/cn.d.ts +13 -0
- package/dist/lib/cn.js +13 -0
- package/dist/lib/cva.d.ts +83 -0
- package/dist/lib/cva.js +178 -0
- package/dist/lib/icons.d.ts +44 -0
- package/dist/lib/icons.js +79 -0
- package/dist/lib/id.d.ts +31 -0
- package/dist/lib/id.js +41 -0
- package/dist/lib/index.d.ts +12 -0
- package/dist/lib/index.js +12 -0
- package/dist/lib/motion.d.ts +31 -0
- package/dist/lib/motion.js +39 -0
- package/dist/lib/props.d.ts +48 -0
- package/dist/lib/props.js +59 -0
- package/dist/lib/styled.d.ts +31 -0
- package/dist/lib/styled.js +39 -0
- package/dist/molecules/Accordion.d.ts +35 -0
- package/dist/molecules/Accordion.js +117 -0
- package/dist/molecules/Alert.d.ts +30 -0
- package/dist/molecules/Alert.js +35 -0
- package/dist/molecules/Attachment.d.ts +39 -0
- package/dist/molecules/Attachment.js +103 -0
- package/dist/molecules/Breadcrumb.d.ts +29 -0
- package/dist/molecules/Breadcrumb.js +73 -0
- package/dist/molecules/Bubble.d.ts +56 -0
- package/dist/molecules/Bubble.js +92 -0
- package/dist/molecules/ButtonGroup.d.ts +23 -0
- package/dist/molecules/ButtonGroup.js +30 -0
- package/dist/molecules/Card.d.ts +17 -0
- package/dist/molecules/Card.js +17 -0
- package/dist/molecules/Collapsible.d.ts +40 -0
- package/dist/molecules/Collapsible.js +71 -0
- package/dist/molecules/Empty.d.ts +16 -0
- package/dist/molecules/Empty.js +16 -0
- package/dist/molecules/Field.d.ts +54 -0
- package/dist/molecules/Field.js +82 -0
- package/dist/molecules/InputGroup.d.ts +33 -0
- package/dist/molecules/InputGroup.js +35 -0
- package/dist/molecules/InputOTP.d.ts +33 -0
- package/dist/molecules/InputOTP.js +140 -0
- package/dist/molecules/Item.d.ts +41 -0
- package/dist/molecules/Item.js +48 -0
- package/dist/molecules/Message.d.ts +43 -0
- package/dist/molecules/Message.js +82 -0
- package/dist/molecules/Pagination.d.ts +41 -0
- package/dist/molecules/Pagination.js +144 -0
- package/dist/molecules/RadioGroup.d.ts +32 -0
- package/dist/molecules/RadioGroup.js +65 -0
- package/dist/molecules/Resizable.d.ts +37 -0
- package/dist/molecules/Resizable.js +136 -0
- package/dist/molecules/Table.d.ts +37 -0
- package/dist/molecules/Table.js +78 -0
- package/dist/molecules/Tabs.d.ts +37 -0
- package/dist/molecules/Tabs.js +109 -0
- package/dist/molecules/ToggleGroup.d.ts +37 -0
- package/dist/molecules/ToggleGroup.js +68 -0
- package/dist/molecules/Typography.d.ts +26 -0
- package/dist/molecules/Typography.js +67 -0
- package/dist/molecules/index.d.ts +37 -0
- package/dist/molecules/index.js +37 -0
- package/dist/organisms/AlertDialog.d.ts +40 -0
- package/dist/organisms/AlertDialog.js +104 -0
- package/dist/organisms/Calendar.d.ts +96 -0
- package/dist/organisms/Calendar.js +353 -0
- package/dist/organisms/Carousel.d.ts +29 -0
- package/dist/organisms/Carousel.js +128 -0
- package/dist/organisms/Chart.d.ts +55 -0
- package/dist/organisms/Chart.js +189 -0
- package/dist/organisms/Combobox.d.ts +41 -0
- package/dist/organisms/Combobox.js +102 -0
- package/dist/organisms/Command.d.ts +46 -0
- package/dist/organisms/Command.js +171 -0
- package/dist/organisms/CommandDialog.d.ts +42 -0
- package/dist/organisms/CommandDialog.js +116 -0
- package/dist/organisms/ContextMenu.d.ts +29 -0
- package/dist/organisms/ContextMenu.js +102 -0
- package/dist/organisms/DataTable.d.ts +50 -0
- package/dist/organisms/DataTable.js +257 -0
- package/dist/organisms/DatePicker.d.ts +34 -0
- package/dist/organisms/DatePicker.js +115 -0
- package/dist/organisms/DateRangePicker.d.ts +34 -0
- package/dist/organisms/DateRangePicker.js +122 -0
- package/dist/organisms/Dialog.d.ts +50 -0
- package/dist/organisms/Dialog.js +116 -0
- package/dist/organisms/Drawer.d.ts +40 -0
- package/dist/organisms/Drawer.js +131 -0
- package/dist/organisms/DropdownMenu.d.ts +30 -0
- package/dist/organisms/DropdownMenu.js +91 -0
- package/dist/organisms/Form.d.ts +114 -0
- package/dist/organisms/Form.js +151 -0
- package/dist/organisms/HoverCard.d.ts +30 -0
- package/dist/organisms/HoverCard.js +68 -0
- package/dist/organisms/Menubar.d.ts +28 -0
- package/dist/organisms/Menubar.js +147 -0
- package/dist/organisms/MessageScroller.d.ts +36 -0
- package/dist/organisms/MessageScroller.js +124 -0
- package/dist/organisms/NavigationMenu.d.ts +41 -0
- package/dist/organisms/NavigationMenu.js +139 -0
- package/dist/organisms/Popover.d.ts +33 -0
- package/dist/organisms/Popover.js +58 -0
- package/dist/organisms/Questionnaire.d.ts +74 -0
- package/dist/organisms/Questionnaire.js +235 -0
- package/dist/organisms/Select.d.ts +47 -0
- package/dist/organisms/Select.js +250 -0
- package/dist/organisms/Sheet.d.ts +34 -0
- package/dist/organisms/Sheet.js +107 -0
- package/dist/organisms/Sidebar.d.ts +100 -0
- package/dist/organisms/Sidebar.js +228 -0
- package/dist/organisms/Toaster.d.ts +67 -0
- package/dist/organisms/Toaster.js +189 -0
- package/dist/organisms/Tooltip.d.ts +39 -0
- package/dist/organisms/Tooltip.js +94 -0
- package/dist/organisms/index.d.ts +40 -0
- package/dist/organisms/index.js +40 -0
- package/dist/primitives/controllable.d.ts +38 -0
- package/dist/primitives/controllable.js +43 -0
- package/dist/primitives/dismissable.d.ts +53 -0
- package/dist/primitives/dismissable.js +158 -0
- package/dist/primitives/floating.d.ts +116 -0
- package/dist/primitives/floating.js +289 -0
- package/dist/primitives/floatingSurface.d.ts +56 -0
- package/dist/primitives/floatingSurface.js +142 -0
- package/dist/primitives/focusTrap.d.ts +47 -0
- package/dist/primitives/focusTrap.js +101 -0
- package/dist/primitives/focusable.d.ts +53 -0
- package/dist/primitives/focusable.js +109 -0
- package/dist/primitives/index.d.ts +27 -0
- package/dist/primitives/index.js +27 -0
- package/dist/primitives/menu.d.ts +102 -0
- package/dist/primitives/menu.js +356 -0
- package/dist/primitives/modalSurface.d.ts +54 -0
- package/dist/primitives/modalSurface.js +146 -0
- package/dist/primitives/portal.d.ts +34 -0
- package/dist/primitives/portal.js +42 -0
- package/dist/primitives/presence.d.ts +45 -0
- package/dist/primitives/presence.js +152 -0
- package/dist/primitives/rovingFocus.d.ts +47 -0
- package/dist/primitives/rovingFocus.js +176 -0
- package/dist/primitives/scrollLock.d.ts +21 -0
- package/dist/primitives/scrollLock.js +75 -0
- package/dist/primitives/typeahead.d.ts +39 -0
- package/dist/primitives/typeahead.js +123 -0
- package/dist/templates/AppShell.d.ts +30 -0
- package/dist/templates/AppShell.js +42 -0
- package/dist/templates/AuthLayout.d.ts +23 -0
- package/dist/templates/AuthLayout.js +42 -0
- package/dist/templates/SettingsLayout.d.ts +27 -0
- package/dist/templates/SettingsLayout.js +42 -0
- package/dist/templates/index.d.ts +16 -0
- package/dist/templates/index.js +16 -0
- package/nebula.css +2 -0
- package/package.json +92 -0
- package/registry.json +1107 -0
- package/src/adapters/css.ts +75 -0
- package/src/adapters/index.ts +40 -0
- package/src/adapters/tailwind.ts +134 -0
- package/src/adapters/types.ts +53 -0
- package/src/adapters/unocss.ts +116 -0
- package/src/atoms/AspectRatio.ts +28 -0
- package/src/atoms/Avatar.ts +67 -0
- package/src/atoms/Badge.ts +46 -0
- package/src/atoms/Button.ts +96 -0
- package/src/atoms/Checkbox.ts +76 -0
- package/src/atoms/Input.ts +76 -0
- package/src/atoms/Kbd.ts +28 -0
- package/src/atoms/Label.ts +38 -0
- package/src/atoms/Marker.ts +79 -0
- package/src/atoms/NativeSelect.ts +115 -0
- package/src/atoms/Progress.ts +64 -0
- package/src/atoms/ScrollArea.ts +53 -0
- package/src/atoms/Separator.ts +36 -0
- package/src/atoms/Skeleton.ts +24 -0
- package/src/atoms/Slider.ts +65 -0
- package/src/atoms/Spinner.ts +28 -0
- package/src/atoms/Switch.ts +56 -0
- package/src/atoms/Textarea.ts +58 -0
- package/src/atoms/Toggle.ts +67 -0
- package/src/atoms/index.ts +62 -0
- package/src/cli/add.ts +126 -0
- package/src/cli/index.ts +22 -0
- package/src/cli/registry.ts +116 -0
- package/src/config.ts +102 -0
- package/src/configure.ts +127 -0
- package/src/index.ts +53 -0
- package/src/lib/children.ts +43 -0
- package/src/lib/cn.ts +14 -0
- package/src/lib/cva.ts +249 -0
- package/src/lib/icons.ts +138 -0
- package/src/lib/id.ts +44 -0
- package/src/lib/index.ts +21 -0
- package/src/lib/motion.ts +48 -0
- package/src/lib/props.ts +83 -0
- package/src/lib/styled.ts +60 -0
- package/src/molecules/Accordion.ts +161 -0
- package/src/molecules/Alert.ts +58 -0
- package/src/molecules/Attachment.ts +132 -0
- package/src/molecules/Breadcrumb.ts +107 -0
- package/src/molecules/Bubble.ts +134 -0
- package/src/molecules/ButtonGroup.ts +55 -0
- package/src/molecules/Card.ts +42 -0
- package/src/molecules/Collapsible.ts +89 -0
- package/src/molecules/Empty.ts +43 -0
- package/src/molecules/Field.ts +131 -0
- package/src/molecules/InputGroup.ts +62 -0
- package/src/molecules/InputOTP.ts +166 -0
- package/src/molecules/Item.ts +89 -0
- package/src/molecules/Message.ts +127 -0
- package/src/molecules/Pagination.ts +197 -0
- package/src/molecules/RadioGroup.ts +104 -0
- package/src/molecules/Resizable.ts +166 -0
- package/src/molecules/Table.ts +118 -0
- package/src/molecules/Tabs.ts +148 -0
- package/src/molecules/ToggleGroup.ts +109 -0
- package/src/molecules/Typography.ts +94 -0
- package/src/molecules/index.ts +144 -0
- package/src/organisms/AlertDialog.ts +133 -0
- package/src/organisms/Calendar.ts +470 -0
- package/src/organisms/Carousel.ts +161 -0
- package/src/organisms/Chart.ts +257 -0
- package/src/organisms/Combobox.ts +140 -0
- package/src/organisms/Command.ts +211 -0
- package/src/organisms/CommandDialog.ts +149 -0
- package/src/organisms/ContextMenu.ts +125 -0
- package/src/organisms/DataTable.ts +328 -0
- package/src/organisms/DatePicker.ts +141 -0
- package/src/organisms/DateRangePicker.ts +149 -0
- package/src/organisms/Dialog.ts +162 -0
- package/src/organisms/Drawer.ts +167 -0
- package/src/organisms/DropdownMenu.ts +112 -0
- package/src/organisms/Form.ts +217 -0
- package/src/organisms/HoverCard.ts +92 -0
- package/src/organisms/Menubar.ts +167 -0
- package/src/organisms/MessageScroller.ts +145 -0
- package/src/organisms/NavigationMenu.ts +184 -0
- package/src/organisms/Popover.ts +84 -0
- package/src/organisms/Questionnaire.ts +322 -0
- package/src/organisms/Select.ts +286 -0
- package/src/organisms/Sheet.ts +144 -0
- package/src/organisms/Sidebar.ts +336 -0
- package/src/organisms/Toaster.ts +246 -0
- package/src/organisms/Tooltip.ts +124 -0
- package/src/organisms/index.ts +134 -0
- package/src/primitives/controllable.ts +64 -0
- package/src/primitives/dismissable.ts +195 -0
- package/src/primitives/floating.ts +453 -0
- package/src/primitives/floatingSurface.ts +209 -0
- package/src/primitives/focusTrap.ts +132 -0
- package/src/primitives/focusable.ts +108 -0
- package/src/primitives/index.ts +88 -0
- package/src/primitives/menu.ts +491 -0
- package/src/primitives/modalSurface.ts +199 -0
- package/src/primitives/portal.ts +61 -0
- package/src/primitives/presence.ts +185 -0
- package/src/primitives/rovingFocus.ts +212 -0
- package/src/primitives/scrollLock.ts +79 -0
- package/src/primitives/typeahead.ts +156 -0
- package/src/templates/AppShell.ts +56 -0
- package/src/templates/AuthLayout.ts +66 -0
- package/src/templates/SettingsLayout.ts +63 -0
- package/src/templates/index.ts +21 -0
- package/theme.css +151 -0
package/dist/lib/id.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable element ids.
|
|
3
|
+
*
|
|
4
|
+
* Radix leans on React's `useId` to wire ARIA relationships — a trigger's
|
|
5
|
+
* `aria-controls` has to name the id its content actually carries. Aurora has
|
|
6
|
+
* no equivalent, and nebula needs one for two reasons: the ARIA wiring above,
|
|
7
|
+
* and element lookup. Aurora templates have no `ref` directive, so a component
|
|
8
|
+
* that must measure or focus a node finds it by id inside `onMount()`.
|
|
9
|
+
*
|
|
10
|
+
* The counter is monotonic per module instance, so the sequence depends only
|
|
11
|
+
* on the order components are constructed in. That order is identical on the
|
|
12
|
+
* server and in the browser for the same tree, which is what makes the ids
|
|
13
|
+
* survive hydration — the same property React's `useId` relies on.
|
|
14
|
+
*
|
|
15
|
+
* `resetIds()` exists for the server: a long-lived process renders many
|
|
16
|
+
* requests, and without a reset the counter climbs forever and every response
|
|
17
|
+
* ships different markup, defeating any HTML cache. Call it once per render
|
|
18
|
+
* pass, before the tree is built.
|
|
19
|
+
*/
|
|
20
|
+
/** Mint an id unique within this render pass. */
|
|
21
|
+
export declare function uid(prefix?: string): string;
|
|
22
|
+
/** Restart the sequence. Call once per SSR render, before building the tree. */
|
|
23
|
+
export declare function resetIds(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Look an element up by the id a component minted for it.
|
|
26
|
+
*
|
|
27
|
+
* Returns `null` off the DOM (SSR) or before mount rather than throwing, so
|
|
28
|
+
* callers can run the same code in both environments. Every consumer inside
|
|
29
|
+
* nebula is in `onMount`, where the node is live.
|
|
30
|
+
*/
|
|
31
|
+
export declare function byId(id: string): HTMLElement | null;
|
package/dist/lib/id.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable element ids.
|
|
3
|
+
*
|
|
4
|
+
* Radix leans on React's `useId` to wire ARIA relationships — a trigger's
|
|
5
|
+
* `aria-controls` has to name the id its content actually carries. Aurora has
|
|
6
|
+
* no equivalent, and nebula needs one for two reasons: the ARIA wiring above,
|
|
7
|
+
* and element lookup. Aurora templates have no `ref` directive, so a component
|
|
8
|
+
* that must measure or focus a node finds it by id inside `onMount()`.
|
|
9
|
+
*
|
|
10
|
+
* The counter is monotonic per module instance, so the sequence depends only
|
|
11
|
+
* on the order components are constructed in. That order is identical on the
|
|
12
|
+
* server and in the browser for the same tree, which is what makes the ids
|
|
13
|
+
* survive hydration — the same property React's `useId` relies on.
|
|
14
|
+
*
|
|
15
|
+
* `resetIds()` exists for the server: a long-lived process renders many
|
|
16
|
+
* requests, and without a reset the counter climbs forever and every response
|
|
17
|
+
* ships different markup, defeating any HTML cache. Call it once per render
|
|
18
|
+
* pass, before the tree is built.
|
|
19
|
+
*/
|
|
20
|
+
let counter = 0;
|
|
21
|
+
/** Mint an id unique within this render pass. */
|
|
22
|
+
export function uid(prefix = "nebula") {
|
|
23
|
+
counter += 1;
|
|
24
|
+
return `${prefix}-${counter}`;
|
|
25
|
+
}
|
|
26
|
+
/** Restart the sequence. Call once per SSR render, before building the tree. */
|
|
27
|
+
export function resetIds() {
|
|
28
|
+
counter = 0;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Look an element up by the id a component minted for it.
|
|
32
|
+
*
|
|
33
|
+
* Returns `null` off the DOM (SSR) or before mount rather than throwing, so
|
|
34
|
+
* callers can run the same code in both environments. Every consumer inside
|
|
35
|
+
* nebula is in `onMount`, where the node is live.
|
|
36
|
+
*/
|
|
37
|
+
export function byId(id) {
|
|
38
|
+
if (typeof document === "undefined")
|
|
39
|
+
return null;
|
|
40
|
+
return document.getElementById(id);
|
|
41
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two class helpers shadcn is built on, plus the prop plumbing Aurora
|
|
3
|
+
* needs in their place.
|
|
4
|
+
*
|
|
5
|
+
* `cn` comes from aurora (clsx + tailwind-merge, already written from scratch
|
|
6
|
+
* there); `cva` is reimplemented here. Between them nebula adds no runtime
|
|
7
|
+
* dependency at all — the same call the workspace made for `cn` itself.
|
|
8
|
+
*/
|
|
9
|
+
export { type ClassValue, clsx, cn, twMerge } from "./cn.js";
|
|
10
|
+
export { type ClassOverrides, type CompoundVariant, cva, type VariantConfig, type VariantProps, type VariantSelection, type VariantShape, } from "./cva.js";
|
|
11
|
+
export { byId, resetIds, uid } from "./id.js";
|
|
12
|
+
export { accessor, callHandler, type Reactive, read, readOr } from "./props.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two class helpers shadcn is built on, plus the prop plumbing Aurora
|
|
3
|
+
* needs in their place.
|
|
4
|
+
*
|
|
5
|
+
* `cn` comes from aurora (clsx + tailwind-merge, already written from scratch
|
|
6
|
+
* there); `cva` is reimplemented here. Between them nebula adds no runtime
|
|
7
|
+
* dependency at all — the same call the workspace made for `cn` itself.
|
|
8
|
+
*/
|
|
9
|
+
export { clsx, cn, twMerge } from "./cn.js";
|
|
10
|
+
export { cva, } from "./cva.js";
|
|
11
|
+
export { byId, resetIds, uid } from "./id.js";
|
|
12
|
+
export { accessor, callHandler, read, readOr } from "./props.js";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enter and exit animations for overlays.
|
|
3
|
+
*
|
|
4
|
+
* shadcn drives these with `animate-in` / `animate-out` from `tw-animate-css`
|
|
5
|
+
* — a Tailwind plugin, and a dependency. nebula declares the four keyframes it
|
|
6
|
+
* needs in `theme.css` and references them through arbitrary animation values,
|
|
7
|
+
* which every one of the three adapters supports and none of them needs a
|
|
8
|
+
* plugin for.
|
|
9
|
+
*
|
|
10
|
+
* The durations are asymmetric on purpose: entering is slower than leaving.
|
|
11
|
+
* A surface appearing wants to be noticed, a surface dismissed wants to be out
|
|
12
|
+
* of the way — matching them makes closing feel sluggish.
|
|
13
|
+
*
|
|
14
|
+
* Every string ends in `motion-reduce:animate-none`. That is not only a
|
|
15
|
+
* courtesy: `onExitFinished` reads the computed style to decide whether to
|
|
16
|
+
* wait, sees no animation, and removes the node immediately. Reduced motion
|
|
17
|
+
* therefore gets an instant close rather than a delayed one, with no branch in
|
|
18
|
+
* the component.
|
|
19
|
+
*/
|
|
20
|
+
import type { Side } from "../primitives/floating.js";
|
|
21
|
+
/** Popovers, menus, selects — scale up from the anchor. */
|
|
22
|
+
export declare const zoomInOut = "data-[state=open]:animate-[nebula-zoom-in_150ms_ease-out] data-[state=closed]:animate-[nebula-zoom-out_120ms_ease-in] motion-reduce:animate-none";
|
|
23
|
+
/** Backdrops and tooltips — no movement, just opacity. */
|
|
24
|
+
export declare const fadeInOut = "data-[state=open]:animate-[nebula-fade-in_150ms_ease-out] data-[state=closed]:animate-[nebula-fade-out_120ms_ease-in] motion-reduce:animate-none";
|
|
25
|
+
/**
|
|
26
|
+
* Panels that slide in from an edge — Sheet, Drawer.
|
|
27
|
+
*
|
|
28
|
+
* The transform is a utility pair rather than a keyframe, because the distance
|
|
29
|
+
* depends on the panel's own size and only `translate-x-full` knows that.
|
|
30
|
+
*/
|
|
31
|
+
export declare function slideFrom(side: Side): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enter and exit animations for overlays.
|
|
3
|
+
*
|
|
4
|
+
* shadcn drives these with `animate-in` / `animate-out` from `tw-animate-css`
|
|
5
|
+
* — a Tailwind plugin, and a dependency. nebula declares the four keyframes it
|
|
6
|
+
* needs in `theme.css` and references them through arbitrary animation values,
|
|
7
|
+
* which every one of the three adapters supports and none of them needs a
|
|
8
|
+
* plugin for.
|
|
9
|
+
*
|
|
10
|
+
* The durations are asymmetric on purpose: entering is slower than leaving.
|
|
11
|
+
* A surface appearing wants to be noticed, a surface dismissed wants to be out
|
|
12
|
+
* of the way — matching them makes closing feel sluggish.
|
|
13
|
+
*
|
|
14
|
+
* Every string ends in `motion-reduce:animate-none`. That is not only a
|
|
15
|
+
* courtesy: `onExitFinished` reads the computed style to decide whether to
|
|
16
|
+
* wait, sees no animation, and removes the node immediately. Reduced motion
|
|
17
|
+
* therefore gets an instant close rather than a delayed one, with no branch in
|
|
18
|
+
* the component.
|
|
19
|
+
*/
|
|
20
|
+
/** Popovers, menus, selects — scale up from the anchor. */
|
|
21
|
+
export const zoomInOut = "data-[state=open]:animate-[nebula-zoom-in_150ms_ease-out] data-[state=closed]:animate-[nebula-zoom-out_120ms_ease-in] motion-reduce:animate-none";
|
|
22
|
+
/** Backdrops and tooltips — no movement, just opacity. */
|
|
23
|
+
export const fadeInOut = "data-[state=open]:animate-[nebula-fade-in_150ms_ease-out] data-[state=closed]:animate-[nebula-fade-out_120ms_ease-in] motion-reduce:animate-none";
|
|
24
|
+
/**
|
|
25
|
+
* Panels that slide in from an edge — Sheet, Drawer.
|
|
26
|
+
*
|
|
27
|
+
* The transform is a utility pair rather than a keyframe, because the distance
|
|
28
|
+
* depends on the panel's own size and only `translate-x-full` knows that.
|
|
29
|
+
*/
|
|
30
|
+
export function slideFrom(side) {
|
|
31
|
+
const axis = side === "left"
|
|
32
|
+
? "data-[state=closed]:-translate-x-full"
|
|
33
|
+
: side === "right"
|
|
34
|
+
? "data-[state=closed]:translate-x-full"
|
|
35
|
+
: side === "top"
|
|
36
|
+
? "data-[state=closed]:-translate-y-full"
|
|
37
|
+
: "data-[state=closed]:translate-y-full";
|
|
38
|
+
return `transition-transform duration-300 ease-in-out data-[state=open]:translate-x-0 data-[state=open]:translate-y-0 ${axis} motion-reduce:transition-none`;
|
|
39
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive prop plumbing.
|
|
3
|
+
*
|
|
4
|
+
* React components take plain values and re-render. Aurora never re-renders —
|
|
5
|
+
* a binding stays live because the value handed to it is a signal or a plain
|
|
6
|
+
* accessor function, which the renderer wraps in an `effect()`. So every
|
|
7
|
+
* nebula prop that can change over time is typed `Reactive<T>`: pass a
|
|
8
|
+
* constant when it never moves, pass `() => count() > 3` when it does.
|
|
9
|
+
*
|
|
10
|
+
* Button({ disabled: true }) // static
|
|
11
|
+
* Button({ disabled: () => !form.valid }) // live
|
|
12
|
+
*
|
|
13
|
+
* `read()` collapses either form to a value. `accessor()` does the opposite —
|
|
14
|
+
* it hands the renderer something it can always subscribe to, which is what
|
|
15
|
+
* you want inside a template so the static case does not silently freeze a
|
|
16
|
+
* binding that a sibling prop makes dynamic.
|
|
17
|
+
*/
|
|
18
|
+
/** A prop value that may be constant or recomputed on demand. */
|
|
19
|
+
export type Reactive<T> = T | (() => T);
|
|
20
|
+
/**
|
|
21
|
+
* Collapse a reactive prop to its current value.
|
|
22
|
+
*
|
|
23
|
+
* An absent prop stays `undefined` rather than throwing, because that is
|
|
24
|
+
* exactly what `cva` wants: an axis left `undefined` falls back to its default
|
|
25
|
+
* variant. It lets a component forward props straight through —
|
|
26
|
+
* `buttonVariants({ variant: read(props.variant) })` — with no per-prop
|
|
27
|
+
* presence check, which is the difference between two lines and ten in every
|
|
28
|
+
* component in the library.
|
|
29
|
+
*/
|
|
30
|
+
export declare function read<T>(value: Reactive<T>): T;
|
|
31
|
+
export declare function read<T>(value: Reactive<T> | undefined): T | undefined;
|
|
32
|
+
/** Collapse an optional reactive prop, falling back when it is absent. */
|
|
33
|
+
export declare function readOr<T>(value: Reactive<T> | undefined, fallback: T): T;
|
|
34
|
+
/**
|
|
35
|
+
* Turn any prop into an accessor the renderer can subscribe to.
|
|
36
|
+
*
|
|
37
|
+
* Templates should bind `${accessor(props.disabled, false)}` rather than
|
|
38
|
+
* `${readOr(props.disabled, false)}`: the second reads once at construction
|
|
39
|
+
* and the attribute never updates again.
|
|
40
|
+
*/
|
|
41
|
+
export declare function accessor<T>(value: Reactive<T> | undefined, fallback: T): () => T;
|
|
42
|
+
/**
|
|
43
|
+
* Call a handler if one was supplied.
|
|
44
|
+
*
|
|
45
|
+
* Saves every component the `props.onClick?.(event)` dance and keeps the
|
|
46
|
+
* optional-callback shape identical across the library.
|
|
47
|
+
*/
|
|
48
|
+
export declare function callHandler<A extends readonly unknown[]>(handler: ((...args: A) => void) | undefined, ...args: A): void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive prop plumbing.
|
|
3
|
+
*
|
|
4
|
+
* React components take plain values and re-render. Aurora never re-renders —
|
|
5
|
+
* a binding stays live because the value handed to it is a signal or a plain
|
|
6
|
+
* accessor function, which the renderer wraps in an `effect()`. So every
|
|
7
|
+
* nebula prop that can change over time is typed `Reactive<T>`: pass a
|
|
8
|
+
* constant when it never moves, pass `() => count() > 3` when it does.
|
|
9
|
+
*
|
|
10
|
+
* Button({ disabled: true }) // static
|
|
11
|
+
* Button({ disabled: () => !form.valid }) // live
|
|
12
|
+
*
|
|
13
|
+
* `read()` collapses either form to a value. `accessor()` does the opposite —
|
|
14
|
+
* it hands the renderer something it can always subscribe to, which is what
|
|
15
|
+
* you want inside a template so the static case does not silently freeze a
|
|
16
|
+
* binding that a sibling prop makes dynamic.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Is this prop the accessor form?
|
|
20
|
+
*
|
|
21
|
+
* A type predicate rather than a cast: `Reactive<T>` where `T` is itself a
|
|
22
|
+
* function type is genuinely ambiguous, and nebula resolves it one way on
|
|
23
|
+
* purpose — a function always means "call me". No nebula prop is typed to
|
|
24
|
+
* receive a function as its *value*; callbacks (`onClick`, `onValueChange`)
|
|
25
|
+
* have their own prop types and never pass through here.
|
|
26
|
+
*/
|
|
27
|
+
function isAccessor(value) {
|
|
28
|
+
return typeof value === "function";
|
|
29
|
+
}
|
|
30
|
+
export function read(value) {
|
|
31
|
+
if (value === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
return isAccessor(value) ? value() : value;
|
|
34
|
+
}
|
|
35
|
+
/** Collapse an optional reactive prop, falling back when it is absent. */
|
|
36
|
+
export function readOr(value, fallback) {
|
|
37
|
+
if (value === undefined)
|
|
38
|
+
return fallback;
|
|
39
|
+
return isAccessor(value) ? value() : value;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Turn any prop into an accessor the renderer can subscribe to.
|
|
43
|
+
*
|
|
44
|
+
* Templates should bind `${accessor(props.disabled, false)}` rather than
|
|
45
|
+
* `${readOr(props.disabled, false)}`: the second reads once at construction
|
|
46
|
+
* and the attribute never updates again.
|
|
47
|
+
*/
|
|
48
|
+
export function accessor(value, fallback) {
|
|
49
|
+
return () => readOr(value, fallback);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Call a handler if one was supplied.
|
|
53
|
+
*
|
|
54
|
+
* Saves every component the `props.onClick?.(event)` dance and keeps the
|
|
55
|
+
* optional-callback shape identical across the library.
|
|
56
|
+
*/
|
|
57
|
+
export function callHandler(handler, ...args) {
|
|
58
|
+
handler?.(...args);
|
|
59
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purely presentational parts.
|
|
3
|
+
*
|
|
4
|
+
* A compound component like Card is one interesting element and half a dozen
|
|
5
|
+
* styled boxes — `CardHeader`, `CardContent`, `CardFooter` and friends carry a
|
|
6
|
+
* class string, a `data-slot`, and nothing else. Written out longhand that is
|
|
7
|
+
* eight near-identical lines each, thirty times over, and the differences that
|
|
8
|
+
* matter get lost in the repetition.
|
|
9
|
+
*
|
|
10
|
+
* So the boxes are declared, not written:
|
|
11
|
+
*
|
|
12
|
+
* export const CardHeader = styledDiv("card-header", "flex flex-col gap-1.5 px-6")
|
|
13
|
+
*
|
|
14
|
+
* Only for parts with no behaviour. The moment one needs an event, a piece of
|
|
15
|
+
* state or an ARIA relationship it gets written out in full — hiding those
|
|
16
|
+
* behind a factory is how a component becomes hard to read, which matters
|
|
17
|
+
* doubly here because the registry copies this source into user projects for
|
|
18
|
+
* them to edit.
|
|
19
|
+
*/
|
|
20
|
+
import { type TemplateResult } from "@c9up/aurora";
|
|
21
|
+
import { type Slot } from "./children.js";
|
|
22
|
+
import { type Reactive } from "./props.js";
|
|
23
|
+
export interface StyledProps {
|
|
24
|
+
children?: Slot;
|
|
25
|
+
class?: Reactive<string>;
|
|
26
|
+
id?: string;
|
|
27
|
+
}
|
|
28
|
+
/** A `<div>` carrying a `data-slot` and a base class list. */
|
|
29
|
+
export declare function styledDiv(name: string, base: string): (props?: StyledProps) => TemplateResult;
|
|
30
|
+
/** The same, as an inline `<span>`. */
|
|
31
|
+
export declare function styledSpan(name: string, base: string): (props?: StyledProps) => TemplateResult;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purely presentational parts.
|
|
3
|
+
*
|
|
4
|
+
* A compound component like Card is one interesting element and half a dozen
|
|
5
|
+
* styled boxes — `CardHeader`, `CardContent`, `CardFooter` and friends carry a
|
|
6
|
+
* class string, a `data-slot`, and nothing else. Written out longhand that is
|
|
7
|
+
* eight near-identical lines each, thirty times over, and the differences that
|
|
8
|
+
* matter get lost in the repetition.
|
|
9
|
+
*
|
|
10
|
+
* So the boxes are declared, not written:
|
|
11
|
+
*
|
|
12
|
+
* export const CardHeader = styledDiv("card-header", "flex flex-col gap-1.5 px-6")
|
|
13
|
+
*
|
|
14
|
+
* Only for parts with no behaviour. The moment one needs an event, a piece of
|
|
15
|
+
* state or an ARIA relationship it gets written out in full — hiding those
|
|
16
|
+
* behind a factory is how a component becomes hard to read, which matters
|
|
17
|
+
* doubly here because the registry copies this source into user projects for
|
|
18
|
+
* them to edit.
|
|
19
|
+
*/
|
|
20
|
+
import { component, html } from "@c9up/aurora";
|
|
21
|
+
import { slot } from "./children.js";
|
|
22
|
+
import { cn } from "./cn.js";
|
|
23
|
+
import { read } from "./props.js";
|
|
24
|
+
/** A `<div>` carrying a `data-slot` and a base class list. */
|
|
25
|
+
export function styledDiv(name, base) {
|
|
26
|
+
return component((props) => html `<div
|
|
27
|
+
data-slot="${name}"
|
|
28
|
+
id="${props.id}"
|
|
29
|
+
class="${() => cn(base, read(props.class))}"
|
|
30
|
+
>${slot(props.children)}</div>`);
|
|
31
|
+
}
|
|
32
|
+
/** The same, as an inline `<span>`. */
|
|
33
|
+
export function styledSpan(name, base) {
|
|
34
|
+
return component((props) => html `<span
|
|
35
|
+
data-slot="${name}"
|
|
36
|
+
id="${props.id}"
|
|
37
|
+
class="${() => cn(base, read(props.class))}"
|
|
38
|
+
>${slot(props.children)}</span>`);
|
|
39
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accordion — a stack of collapsible sections.
|
|
3
|
+
*
|
|
4
|
+
* Data-driven rather than composed: an accordion is a list, and describing it
|
|
5
|
+
* as one is both shorter to write and the only shape that lets the group
|
|
6
|
+
* enforce `type: "single"` — which needs to know about every section at once,
|
|
7
|
+
* something Radix can only do through context.
|
|
8
|
+
*
|
|
9
|
+
* The keyboard behaviour is the WAI-ARIA accordion pattern, delegated to
|
|
10
|
+
* `rovingFocus` over the headers: arrows move between sections, Home and End
|
|
11
|
+
* jump to the ends, and the headers are one tab stop rather than one each.
|
|
12
|
+
*/
|
|
13
|
+
import type { Child, Slot } from "../lib/children.js";
|
|
14
|
+
import { type Reactive } from "../lib/props.js";
|
|
15
|
+
export interface AccordionItem {
|
|
16
|
+
/** Stable key. Used for the open-state set and for the ARIA ids. */
|
|
17
|
+
value: string;
|
|
18
|
+
/** The header content. */
|
|
19
|
+
trigger: Child;
|
|
20
|
+
/** The panel content. */
|
|
21
|
+
content: Slot;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface AccordionProps {
|
|
25
|
+
items: readonly AccordionItem[];
|
|
26
|
+
/** `"single"` closes the open section when another opens. Default `"single"`. */
|
|
27
|
+
type?: "single" | "multiple";
|
|
28
|
+
/** Open at first render. A string, or several for `type: "multiple"`. */
|
|
29
|
+
defaultValue?: string | readonly string[];
|
|
30
|
+
/** `"single"` accordions can normally be closed entirely. */
|
|
31
|
+
collapsible?: boolean;
|
|
32
|
+
onValueChange?: (open: readonly string[]) => void;
|
|
33
|
+
class?: Reactive<string>;
|
|
34
|
+
}
|
|
35
|
+
export declare const Accordion: (props?: AccordionProps | undefined) => import("@c9up/aurora").TemplateResult;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accordion — a stack of collapsible sections.
|
|
3
|
+
*
|
|
4
|
+
* Data-driven rather than composed: an accordion is a list, and describing it
|
|
5
|
+
* as one is both shorter to write and the only shape that lets the group
|
|
6
|
+
* enforce `type: "single"` — which needs to know about every section at once,
|
|
7
|
+
* something Radix can only do through context.
|
|
8
|
+
*
|
|
9
|
+
* The keyboard behaviour is the WAI-ARIA accordion pattern, delegated to
|
|
10
|
+
* `rovingFocus` over the headers: arrows move between sections, Home and End
|
|
11
|
+
* jump to the ends, and the headers are one tab stop rather than one each.
|
|
12
|
+
*/
|
|
13
|
+
import { component, html, onMount, onUnmount, signal } from "@c9up/aurora";
|
|
14
|
+
import { slot } from "../lib/children.js";
|
|
15
|
+
import { cn } from "../lib/cn.js";
|
|
16
|
+
import { ChevronDownIcon } from "../lib/icons.js";
|
|
17
|
+
import { uid } from "../lib/id.js";
|
|
18
|
+
import { read } from "../lib/props.js";
|
|
19
|
+
import { rovingFocus } from "../primitives/rovingFocus.js";
|
|
20
|
+
export const Accordion = component((props) => {
|
|
21
|
+
const type = props.type ?? "single";
|
|
22
|
+
const open = signal(normaliseInitial(props.defaultValue));
|
|
23
|
+
const rootId = uid("accordion");
|
|
24
|
+
function isOpen(value) {
|
|
25
|
+
return open().includes(value);
|
|
26
|
+
}
|
|
27
|
+
function toggle(value) {
|
|
28
|
+
const current = open();
|
|
29
|
+
const next = nextOpenSet(current, value, type, props.collapsible !== false);
|
|
30
|
+
open(next);
|
|
31
|
+
props.onValueChange?.(next);
|
|
32
|
+
}
|
|
33
|
+
// Roving focus is attached after mount because it queries the container for
|
|
34
|
+
// its items, and the container does not exist until then.
|
|
35
|
+
let group;
|
|
36
|
+
onMount(() => {
|
|
37
|
+
group = rovingFocus({
|
|
38
|
+
container: () => document.getElementById(rootId),
|
|
39
|
+
itemSelector: "[data-slot='accordion-trigger']",
|
|
40
|
+
orientation: "vertical",
|
|
41
|
+
});
|
|
42
|
+
group.sync();
|
|
43
|
+
});
|
|
44
|
+
onUnmount(() => group?.destroy());
|
|
45
|
+
return html `<div
|
|
46
|
+
data-slot="accordion"
|
|
47
|
+
id="${rootId}"
|
|
48
|
+
class="${() => cn("flex w-full flex-col", read(props.class))}"
|
|
49
|
+
>
|
|
50
|
+
${props.items.map((item) => renderItem(item, isOpen, toggle))}
|
|
51
|
+
</div>`;
|
|
52
|
+
});
|
|
53
|
+
function renderItem(item, isOpen, toggle) {
|
|
54
|
+
const triggerId = uid("accordion-trigger");
|
|
55
|
+
const panelId = uid("accordion-panel");
|
|
56
|
+
const state = () => (isOpen(item.value) ? "open" : "closed");
|
|
57
|
+
return html `<div
|
|
58
|
+
data-slot="accordion-item"
|
|
59
|
+
data-state="${state}"
|
|
60
|
+
class="border-b last:border-b-0"
|
|
61
|
+
>
|
|
62
|
+
<h3 class="flex">
|
|
63
|
+
<button
|
|
64
|
+
type="button"
|
|
65
|
+
data-slot="accordion-trigger"
|
|
66
|
+
data-nebula-item
|
|
67
|
+
data-state="${state}"
|
|
68
|
+
data-disabled="${item.disabled === true ? "" : undefined}"
|
|
69
|
+
id="${triggerId}"
|
|
70
|
+
aria-expanded="${() => (isOpen(item.value) ? "true" : "false")}"
|
|
71
|
+
aria-controls="${panelId}"
|
|
72
|
+
?disabled="${item.disabled === true}"
|
|
73
|
+
class="focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium outline-none transition-all hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180"
|
|
74
|
+
@click="${() => toggle(item.value)}"
|
|
75
|
+
>
|
|
76
|
+
${item.trigger}
|
|
77
|
+
${ChevronDownIcon({
|
|
78
|
+
class: "text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200",
|
|
79
|
+
})}
|
|
80
|
+
</button>
|
|
81
|
+
</h3>
|
|
82
|
+
<div
|
|
83
|
+
data-slot="accordion-content"
|
|
84
|
+
id="${panelId}"
|
|
85
|
+
role="region"
|
|
86
|
+
aria-labelledby="${triggerId}"
|
|
87
|
+
?inert="${() => !isOpen(item.value)}"
|
|
88
|
+
class="grid text-sm transition-[grid-template-rows] duration-200 ease-out motion-reduce:transition-none"
|
|
89
|
+
style="${() => `grid-template-rows: ${isOpen(item.value) ? "1fr" : "0fr"}`}"
|
|
90
|
+
>
|
|
91
|
+
<div class="overflow-hidden"><div class="pt-0 pb-4">${slot(item.content)}</div></div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>`;
|
|
94
|
+
}
|
|
95
|
+
function normaliseInitial(value) {
|
|
96
|
+
if (value === undefined)
|
|
97
|
+
return [];
|
|
98
|
+
return typeof value === "string" ? [value] : value;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The open set after activating `value`.
|
|
102
|
+
*
|
|
103
|
+
* `collapsible: false` on a single accordion is what stops the last open
|
|
104
|
+
* section from closing — the pattern used when one section must always be
|
|
105
|
+
* showing, and the reason this is not simply a toggle.
|
|
106
|
+
*/
|
|
107
|
+
function nextOpenSet(current, value, type, collapsible) {
|
|
108
|
+
const isOpen = current.includes(value);
|
|
109
|
+
if (type === "multiple") {
|
|
110
|
+
return isOpen
|
|
111
|
+
? current.filter((entry) => entry !== value)
|
|
112
|
+
: [...current, value];
|
|
113
|
+
}
|
|
114
|
+
if (isOpen)
|
|
115
|
+
return collapsible ? [] : current;
|
|
116
|
+
return [value];
|
|
117
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alert — an inline message about the surrounding content.
|
|
3
|
+
*
|
|
4
|
+
* `role="alert"` only for the destructive variant. The role is a live region:
|
|
5
|
+
* it interrupts a screen reader the moment the element appears. That is right
|
|
6
|
+
* for an error and wrong for the informational variant, which would talk over
|
|
7
|
+
* whatever the user was reading to announce something they did not ask about.
|
|
8
|
+
*
|
|
9
|
+
* The grid layout is what lets an optional leading icon align with the title
|
|
10
|
+
* while the description wraps under both, without either part knowing whether
|
|
11
|
+
* the other is present.
|
|
12
|
+
*/
|
|
13
|
+
import { type Slot } from "../lib/children.js";
|
|
14
|
+
import { type VariantProps } from "../lib/cva.js";
|
|
15
|
+
import { type Reactive } from "../lib/props.js";
|
|
16
|
+
export declare const alertVariants: (props?: (import("../index.js").VariantSelection<{
|
|
17
|
+
variant: {
|
|
18
|
+
default: string;
|
|
19
|
+
destructive: string;
|
|
20
|
+
};
|
|
21
|
+
}> & import("../index.js").ClassOverrides) | undefined) => string;
|
|
22
|
+
export type AlertVariants = VariantProps<typeof alertVariants>;
|
|
23
|
+
export interface AlertProps {
|
|
24
|
+
children?: Slot;
|
|
25
|
+
variant?: Reactive<AlertVariants["variant"]>;
|
|
26
|
+
class?: Reactive<string>;
|
|
27
|
+
}
|
|
28
|
+
export declare const Alert: (props?: AlertProps | undefined) => import("@c9up/aurora").TemplateResult;
|
|
29
|
+
export declare const AlertTitle: (props?: import("./Card.js").CardProps) => import("@c9up/aurora").TemplateResult;
|
|
30
|
+
export declare const AlertDescription: (props?: import("./Card.js").CardProps) => import("@c9up/aurora").TemplateResult;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alert — an inline message about the surrounding content.
|
|
3
|
+
*
|
|
4
|
+
* `role="alert"` only for the destructive variant. The role is a live region:
|
|
5
|
+
* it interrupts a screen reader the moment the element appears. That is right
|
|
6
|
+
* for an error and wrong for the informational variant, which would talk over
|
|
7
|
+
* whatever the user was reading to announce something they did not ask about.
|
|
8
|
+
*
|
|
9
|
+
* The grid layout is what lets an optional leading icon align with the title
|
|
10
|
+
* while the description wraps under both, without either part knowing whether
|
|
11
|
+
* the other is present.
|
|
12
|
+
*/
|
|
13
|
+
import { component, html } from "@c9up/aurora";
|
|
14
|
+
import { slot } from "../lib/children.js";
|
|
15
|
+
import { cva } from "../lib/cva.js";
|
|
16
|
+
import { read, readOr } from "../lib/props.js";
|
|
17
|
+
import { styledDiv } from "../lib/styled.js";
|
|
18
|
+
export const alertVariants = cva("relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", {
|
|
19
|
+
variants: {
|
|
20
|
+
variant: {
|
|
21
|
+
default: "bg-card text-card-foreground",
|
|
22
|
+
destructive: "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: { variant: "default" },
|
|
26
|
+
});
|
|
27
|
+
export const Alert = component((props) => {
|
|
28
|
+
return html `<div
|
|
29
|
+
data-slot="alert"
|
|
30
|
+
role="${() => (readOr(props.variant, "default") === "destructive" ? "alert" : "note")}"
|
|
31
|
+
class="${() => alertVariants({ variant: read(props.variant), class: read(props.class) })}"
|
|
32
|
+
>${slot(props.children)}</div>`;
|
|
33
|
+
});
|
|
34
|
+
export const AlertTitle = styledDiv("alert-title", "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight");
|
|
35
|
+
export const AlertDescription = styledDiv("alert-description", "text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed");
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attachment — a file carried by a message.
|
|
3
|
+
*
|
|
4
|
+
* Two shapes from one component: an image renders as a thumbnail, anything
|
|
5
|
+
* else as a chip with a name and a size. Splitting them into two components
|
|
6
|
+
* would push the choice onto the caller, who usually has a MIME type and no
|
|
7
|
+
* opinion.
|
|
8
|
+
*
|
|
9
|
+
* The size is formatted in binary units because that is what a file manager
|
|
10
|
+
* shows for the same file — a "1.2 MB" here and a "1.1 MiB" there for one
|
|
11
|
+
* upload reads as a bug.
|
|
12
|
+
*
|
|
13
|
+
* A removable attachment is a `<button>` beside the link, never a click
|
|
14
|
+
* handler on the chip itself. Merging the two makes "open" and "delete" the
|
|
15
|
+
* same gesture, distinguished only by where you land.
|
|
16
|
+
*/
|
|
17
|
+
import { type Reactive } from "../lib/props.js";
|
|
18
|
+
export interface AttachmentProps {
|
|
19
|
+
name: string;
|
|
20
|
+
/** Bytes. Omitted for something not yet uploaded. */
|
|
21
|
+
size?: number;
|
|
22
|
+
/** MIME type. Anything under `image/` renders as a thumbnail. */
|
|
23
|
+
type?: string;
|
|
24
|
+
/** Opens the file. Without it the chip is inert. */
|
|
25
|
+
href?: string;
|
|
26
|
+
/** Thumbnail source, for an image. Defaults to `href`. */
|
|
27
|
+
previewSrc?: string;
|
|
28
|
+
/** Shows a remove button. */
|
|
29
|
+
onRemove?: () => void;
|
|
30
|
+
class?: Reactive<string>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Human-readable byte count, binary units.
|
|
34
|
+
*
|
|
35
|
+
* Deliberately not `Intl.NumberFormat`'s `unit: "byte"` style: it only speaks
|
|
36
|
+
* decimal units (kB, MB), which disagrees with every desktop file manager.
|
|
37
|
+
*/
|
|
38
|
+
export declare function formatBytes(bytes: number): string;
|
|
39
|
+
export declare const Attachment: (props?: AttachmentProps | undefined) => import("@c9up/aurora").TemplateResult;
|