@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/src/configure.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ream configure @c9up/nebula` — the house setup hook.
|
|
3
|
+
*
|
|
4
|
+
* Every package in this workspace is installed the same way: `ream add <pkg>`
|
|
5
|
+
* installs it and dispatches to this hook, which writes the files the package
|
|
6
|
+
* needs through the codemods the CLI hands in. nebula follows that rather than
|
|
7
|
+
* shipping a setup command of its own — one way to install a ream package, not
|
|
8
|
+
* one per package.
|
|
9
|
+
*
|
|
10
|
+
* Pass the adapter through the installer:
|
|
11
|
+
*
|
|
12
|
+
* ream add @c9up/nebula --adapter unocss
|
|
13
|
+
*
|
|
14
|
+
* There is no provider to register. A provider binds runtime services into the
|
|
15
|
+
* container, and nebula has none: its components are client-side templates and
|
|
16
|
+
* its adapters run at build time. An empty provider would be ceremony.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { adapterFor, isAdapterName } from "./adapters/index.js";
|
|
20
|
+
import { type AdapterName, resolveConfig } from "./config.js";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The subset of the CLI's codemods this hook uses.
|
|
24
|
+
*
|
|
25
|
+
* Declared structurally rather than imported: `@c9up/ream-cli` is a Rust
|
|
26
|
+
* binary that injects this object at runtime, so there is no type to import
|
|
27
|
+
* and a dependency on the CLI would be a lie. Same shape the other packages'
|
|
28
|
+
* hooks declare.
|
|
29
|
+
*/
|
|
30
|
+
interface Codemods {
|
|
31
|
+
writeFile(
|
|
32
|
+
filePath: string,
|
|
33
|
+
content: string,
|
|
34
|
+
options?: { force?: boolean },
|
|
35
|
+
): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Flags forwarded from `ream add` / `ream configure`, as the CLI encodes them. */
|
|
39
|
+
type Flags = Record<string, string[] | undefined>;
|
|
40
|
+
|
|
41
|
+
function configFile(adapter: AdapterName): string {
|
|
42
|
+
return `import { defineConfig } from '@c9up/nebula'
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* nebula — component registry and style adapter.
|
|
46
|
+
*
|
|
47
|
+
* Changing \`adapter\` and re-running \`ream configure @c9up/nebula\` swaps the
|
|
48
|
+
* CSS engine. The components themselves are untouched: all three adapters
|
|
49
|
+
* consume the same class names.
|
|
50
|
+
*/
|
|
51
|
+
export default defineConfig({
|
|
52
|
+
adapter: '${adapter}',
|
|
53
|
+
paths: {
|
|
54
|
+
// Where \`ream nebula:add\` copies components. The atomic layers live under it.
|
|
55
|
+
components: 'resources/pages',
|
|
56
|
+
css: 'resources/css/app.css',
|
|
57
|
+
output: 'public/app.css',
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Read the adapter from the forwarded flags.
|
|
65
|
+
*
|
|
66
|
+
* An unrecognised name is refused rather than silently defaulted: a typo in
|
|
67
|
+
* `--adapter tailwnid` would otherwise write a Tailwind setup and leave the
|
|
68
|
+
* user hunting for why their UnoCSS config never appeared.
|
|
69
|
+
*/
|
|
70
|
+
function adapterFrom(flags: Flags): AdapterName {
|
|
71
|
+
const requested = flags.adapter?.[0];
|
|
72
|
+
if (requested === undefined) return "tailwind";
|
|
73
|
+
if (!isAdapterName(requested)) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`[@c9up/nebula] unknown adapter "${requested}" — one of tailwind, unocss, css`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return requested;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function configure(
|
|
82
|
+
codemods: Codemods,
|
|
83
|
+
flags: Flags = {},
|
|
84
|
+
): Promise<void> {
|
|
85
|
+
const name = adapterFrom(flags);
|
|
86
|
+
const adapter = adapterFor(name);
|
|
87
|
+
const config = resolveConfig({ adapter: name });
|
|
88
|
+
|
|
89
|
+
await codemods.writeFile("config/nebula.ts", configFile(name));
|
|
90
|
+
for (const file of adapter.files(config)) {
|
|
91
|
+
await codemods.writeFile(file.path, file.contents);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// On stderr, and never installed on the user's behalf. nebula declares no
|
|
95
|
+
// CSS dependency at all — the app owns its build tooling, and a UI library
|
|
96
|
+
// quietly adding one to someone's dependency tree is how a tree gets away
|
|
97
|
+
// from them.
|
|
98
|
+
const lines = [
|
|
99
|
+
"",
|
|
100
|
+
"[@c9up/nebula] configured with the " + name + " adapter.",
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
if (adapter.packages.length > 0) {
|
|
104
|
+
lines.push(
|
|
105
|
+
" Install the engine yourself:",
|
|
106
|
+
` pnpm add -D ${adapter.packages.join(" ")}`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const commands = adapter.commands(config);
|
|
111
|
+
if (commands === null) {
|
|
112
|
+
lines.push(" No build step — the stylesheet ships prebuilt.");
|
|
113
|
+
} else {
|
|
114
|
+
lines.push(
|
|
115
|
+
" Register the build in config/assets.ts:",
|
|
116
|
+
` build: ${commands.build.command} ${commands.build.args.join(" ")}`,
|
|
117
|
+
` devServer: ${commands.dev.command} ${commands.dev.args.join(" ")}`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
lines.push(
|
|
122
|
+
" Then add components with `ream nebula:add button card` — they are copied",
|
|
123
|
+
" into your project and are yours to edit.",
|
|
124
|
+
"",
|
|
125
|
+
);
|
|
126
|
+
process.stderr.write(lines.join("\n"));
|
|
127
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @c9up/nebula — shadcn/ui, ported to Aurora, organised as atomic design.
|
|
3
|
+
*
|
|
4
|
+
* Three things are worth knowing before reading further.
|
|
5
|
+
*
|
|
6
|
+
* **It adds no runtime dependency.** shadcn stands on Radix, `clsx`,
|
|
7
|
+
* `tailwind-merge`, `class-variance-authority`, `lucide-react`,
|
|
8
|
+
* `@floating-ui/dom`, `cmdk`, `sonner`, `recharts`, `@tanstack/react-table` and
|
|
9
|
+
* `react-day-picker`. None of them are React-agnostic, and the workspace had
|
|
10
|
+
* already made the call that `cn` was worth writing by hand rather than
|
|
11
|
+
* installing two packages. So `cva` is reimplemented, the Radix behaviour layer
|
|
12
|
+
* lives in `primitives/`, the placement engine is `primitives/floating.ts`, the
|
|
13
|
+
* icons are inlined, and the date maths is `Date` and `Intl`.
|
|
14
|
+
*
|
|
15
|
+
* **Compound components take data, not children.** shadcn composes through
|
|
16
|
+
* React context — `<Tabs><TabsList><TabsTrigger>`. Aurora has no context, and
|
|
17
|
+
* the workarounds are worse than the problem, so those components take an
|
|
18
|
+
* `items` array and named slots. The rendered markup is unchanged, which means
|
|
19
|
+
* shadcn's CSS and its examples still read across.
|
|
20
|
+
*
|
|
21
|
+
* **The atomic layer is a property of the component.** An atom renders its own
|
|
22
|
+
* markup and composes nothing from nebula; a molecule assembles atoms or owns
|
|
23
|
+
* state spanning several elements; an organism portals, traps focus, or floats;
|
|
24
|
+
* a template is page layout. `nebula add button` knows Button is an atom and
|
|
25
|
+
* puts it in `atoms/` without being told.
|
|
26
|
+
*
|
|
27
|
+
* Import from the layer barrels — `@c9up/nebula/atoms` — or take the source
|
|
28
|
+
* with `nebula add`, which is the mode this library is really built for.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
export * from "./adapters/index.js";
|
|
32
|
+
export * from "./atoms/index.js";
|
|
33
|
+
export {
|
|
34
|
+
type AdapterName,
|
|
35
|
+
defaultPaths,
|
|
36
|
+
defineConfig,
|
|
37
|
+
isLayer,
|
|
38
|
+
type Layer,
|
|
39
|
+
layers,
|
|
40
|
+
type NebulaConfig,
|
|
41
|
+
type NebulaPaths,
|
|
42
|
+
type ResolvedNebulaConfig,
|
|
43
|
+
resolveConfig,
|
|
44
|
+
} from "./config.js";
|
|
45
|
+
export { type Child, type Slot, slot } from "./lib/children.js";
|
|
46
|
+
export * from "./lib/icons.js";
|
|
47
|
+
export * from "./lib/index.js";
|
|
48
|
+
export { fadeInOut, slideFrom, zoomInOut } from "./lib/motion.js";
|
|
49
|
+
export { type StyledProps, styledDiv, styledSpan } from "./lib/styled.js";
|
|
50
|
+
export * from "./molecules/index.js";
|
|
51
|
+
export * from "./organisms/index.js";
|
|
52
|
+
export * from "./primitives/index.js";
|
|
53
|
+
export * from "./templates/index.js";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a component accepts as content.
|
|
3
|
+
*
|
|
4
|
+
* Aurora's renderer already handles the whole union in a text slot: nested
|
|
5
|
+
* templates, raw nodes, primitives, and arrays of any of those, with `null`,
|
|
6
|
+
* `undefined` and `false` rendering nothing. `Child` names that union so a
|
|
7
|
+
* component's props say what they mean instead of falling back to `unknown`,
|
|
8
|
+
* and so passing a value the renderer would silently drop is a type error at
|
|
9
|
+
* the call site rather than a blank space on the page.
|
|
10
|
+
*
|
|
11
|
+
* `Slot` is the reactive form. Content that changes must arrive as an accessor
|
|
12
|
+
* — Aurora never re-renders a component, so a plain value read at setup is
|
|
13
|
+
* frozen for the lifetime of the node.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { TemplateResult } from "@c9up/aurora";
|
|
17
|
+
import type { Reactive } from "./props.js";
|
|
18
|
+
|
|
19
|
+
export type Child =
|
|
20
|
+
| TemplateResult
|
|
21
|
+
| Node
|
|
22
|
+
| string
|
|
23
|
+
| number
|
|
24
|
+
| boolean
|
|
25
|
+
| null
|
|
26
|
+
| undefined
|
|
27
|
+
| readonly Child[];
|
|
28
|
+
|
|
29
|
+
/** Content that may be constant or recomputed. */
|
|
30
|
+
export type Slot = Reactive<Child>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Bind content into a template so it stays live.
|
|
34
|
+
*
|
|
35
|
+
* Returns the accessor form unchanged and wraps a constant in one. Templates
|
|
36
|
+
* should always interpolate `${slot(props.children)}`: handing the renderer a
|
|
37
|
+
* bare value works until a sibling prop makes the content dynamic, at which
|
|
38
|
+
* point the binding quietly stops updating and nothing points at why.
|
|
39
|
+
*/
|
|
40
|
+
export function slot(content: Slot | undefined): () => Child {
|
|
41
|
+
if (content === undefined) return () => null;
|
|
42
|
+
return typeof content === "function" ? content : () => content;
|
|
43
|
+
}
|
package/src/lib/cn.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Class composition — re-exported from Aurora rather than reimplemented here.
|
|
3
|
+
*
|
|
4
|
+
* `@c9up/aurora` already ships `clsx` + `tailwind-merge` written from scratch
|
|
5
|
+
* with no dependencies (its `src/cn.ts`, targeting the Tailwind v4 utility
|
|
6
|
+
* set). nebula is a peer of aurora, never a fork of it: one class-merge
|
|
7
|
+
* implementation in the workspace, one place to fix a mis-grouped utility.
|
|
8
|
+
*
|
|
9
|
+
* This module exists so every nebula component imports `./lib/cn.js` and not
|
|
10
|
+
* `@c9up/aurora` directly. That indirection is what lets the registry rewrite
|
|
11
|
+
* a single import line when it copies a component into a host app.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export { type ClassValue, clsx, cn, twMerge } from "@c9up/aurora";
|
package/src/lib/cva.ts
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cva` — class-variance-authority, reimplemented from scratch with ZERO
|
|
3
|
+
* dependencies.
|
|
4
|
+
*
|
|
5
|
+
* shadcn/ui is built on two class helpers: `cn` (clsx + tailwind-merge) and
|
|
6
|
+
* `cva` (variant → class-list resolution). Aurora already ships `cn` written
|
|
7
|
+
* from scratch in `@c9up/aurora` (src/cn.ts), so this file is the other half.
|
|
8
|
+
* Between them, nebula pulls in no runtime dependency at all.
|
|
9
|
+
*
|
|
10
|
+
* const button = cva(
|
|
11
|
+
* "inline-flex items-center rounded-md text-sm font-medium",
|
|
12
|
+
* {
|
|
13
|
+
* variants: {
|
|
14
|
+
* variant: { default: "bg-primary text-primary-foreground",
|
|
15
|
+
* ghost: "hover:bg-accent" },
|
|
16
|
+
* size: { sm: "h-8 px-3", lg: "h-10 px-8" },
|
|
17
|
+
* },
|
|
18
|
+
* compoundVariants: [
|
|
19
|
+
* { variant: "ghost", size: "sm", class: "px-2" },
|
|
20
|
+
* ],
|
|
21
|
+
* defaultVariants: { variant: "default", size: "sm" },
|
|
22
|
+
* },
|
|
23
|
+
* )
|
|
24
|
+
*
|
|
25
|
+
* button() // base + default variants
|
|
26
|
+
* button({ variant: "ghost" }) // ghost, still size sm
|
|
27
|
+
* button({ size: "lg", class: "w-full" }) // caller classes win
|
|
28
|
+
*
|
|
29
|
+
* Differences from the upstream package, both deliberate:
|
|
30
|
+
*
|
|
31
|
+
* 1. The result runs through Aurora's `cn`, so a variant that sets `px-2`
|
|
32
|
+
* genuinely overrides a base `px-3` instead of emitting both and leaving
|
|
33
|
+
* the winner to CSS source order. Upstream cva only concatenates; every
|
|
34
|
+
* real shadcn component then wraps the call in `cn(...)` to get here
|
|
35
|
+
* anyway. Doing it inside removes that ceremony from ~50 components.
|
|
36
|
+
* 2. `class` and `className` are both accepted. Aurora templates use `class`;
|
|
37
|
+
* `className` exists only so code pasted over from a React codebase keeps
|
|
38
|
+
* working.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
import { type ClassValue, cn } from "./cn.js";
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* One variant axis: a variant name mapped to the classes each of its values
|
|
45
|
+
* contributes. `{ size: { sm: "h-8", lg: "h-10" } }` is one axis with two
|
|
46
|
+
* values.
|
|
47
|
+
*/
|
|
48
|
+
export type VariantShape = Record<string, Record<string, ClassValue>>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The value accepted for one axis.
|
|
52
|
+
*
|
|
53
|
+
* An axis keyed by `"true"` / `"false"` is a boolean axis — the caller passes
|
|
54
|
+
* a real `boolean`, not the string. That mapping is what lets
|
|
55
|
+
* `{ disabled: { true: "opacity-50" } }` be driven by `disabled: true`.
|
|
56
|
+
*/
|
|
57
|
+
type VariantValue<T> =
|
|
58
|
+
Extract<keyof T, string> extends "true" | "false"
|
|
59
|
+
? boolean
|
|
60
|
+
: Extract<keyof T, string>;
|
|
61
|
+
|
|
62
|
+
/** Props selecting one value per axis. Every axis is optional. */
|
|
63
|
+
export type VariantSelection<V extends VariantShape> = {
|
|
64
|
+
[K in keyof V]?: VariantValue<V[K]> | null | undefined;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* A compound rule matches when EVERY axis it names matches. An axis may list
|
|
69
|
+
* several accepted values, in which case any of them matches.
|
|
70
|
+
*/
|
|
71
|
+
export type CompoundVariant<V extends VariantShape> = {
|
|
72
|
+
[K in keyof V]?: VariantValue<V[K]> | ReadonlyArray<VariantValue<V[K]>>;
|
|
73
|
+
} & ClassOverrides;
|
|
74
|
+
|
|
75
|
+
/** Extra keys every generated function accepts on top of its own axes. */
|
|
76
|
+
export interface ClassOverrides {
|
|
77
|
+
class?: ClassValue;
|
|
78
|
+
className?: ClassValue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface VariantConfig<V extends VariantShape> {
|
|
82
|
+
variants?: V;
|
|
83
|
+
compoundVariants?: ReadonlyArray<CompoundVariant<V>>;
|
|
84
|
+
defaultVariants?: VariantSelection<V>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** The props a `cva()` result accepts, minus the two class escape hatches. */
|
|
88
|
+
export type VariantProps<F> = F extends (props?: infer P) => string
|
|
89
|
+
? Omit<NonNullable<P>, "class" | "className">
|
|
90
|
+
: never;
|
|
91
|
+
|
|
92
|
+
/** A compound rule flattened into "conditions + classes it contributes". */
|
|
93
|
+
interface CompoundRule {
|
|
94
|
+
/** Each entry is one axis and the set of values that satisfy it. */
|
|
95
|
+
readonly conditions: ReadonlyArray<readonly [string, readonly string[]]>;
|
|
96
|
+
readonly classes: readonly ClassValue[];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Build a variant resolver. Returns a function from a variant selection to a
|
|
101
|
+
* single, conflict-resolved class string.
|
|
102
|
+
*/
|
|
103
|
+
export function cva<V extends VariantShape>(
|
|
104
|
+
base?: ClassValue,
|
|
105
|
+
config?: VariantConfig<V>,
|
|
106
|
+
): (props?: VariantSelection<V> & ClassOverrides) => string {
|
|
107
|
+
// Widening to the non-generic shapes up front is what keeps the body free
|
|
108
|
+
// of casts: `V` cannot be indexed by a plain `string`, `VariantShape` can.
|
|
109
|
+
const variants: VariantShape = config?.variants ?? {};
|
|
110
|
+
const axes = Object.keys(variants);
|
|
111
|
+
const defaults = toValueMap(config?.defaultVariants);
|
|
112
|
+
const compounds = normaliseCompounds(config?.compoundVariants);
|
|
113
|
+
|
|
114
|
+
return (props?: VariantSelection<V> & ClassOverrides): string => {
|
|
115
|
+
const selection = selectionFor(defaults, props);
|
|
116
|
+
const parts: ClassValue[] = [base];
|
|
117
|
+
|
|
118
|
+
for (const axis of axes) {
|
|
119
|
+
const chosen = selection[axis];
|
|
120
|
+
if (chosen === undefined) continue;
|
|
121
|
+
// Indexed by the *string form* of the value, so a boolean axis reaches
|
|
122
|
+
// its `"true"` / `"false"` entry here.
|
|
123
|
+
const classesForValue = variants[axis]?.[chosen];
|
|
124
|
+
if (classesForValue !== undefined) parts.push(classesForValue);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (const rule of compounds) {
|
|
128
|
+
if (satisfies(rule, selection)) parts.push(...rule.classes);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Caller overrides come last so they win the tailwind-merge pass.
|
|
132
|
+
parts.push(props?.class, props?.className);
|
|
133
|
+
return cn(parts);
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Read an object's own enumerable entries with honest `unknown` values.
|
|
139
|
+
*
|
|
140
|
+
* Variant selections are generic mapped types, which TypeScript will not let
|
|
141
|
+
* you index with a plain `string`. Funnelling every read through one helper
|
|
142
|
+
* typed `object → [string, unknown][]` gets the values out without a cast at
|
|
143
|
+
* any call site, and forces each one to narrow before use.
|
|
144
|
+
*/
|
|
145
|
+
function entriesOf(source: object): ReadonlyArray<readonly [string, unknown]> {
|
|
146
|
+
return Object.entries(source);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Collapse a selection object down to `axis → string value`.
|
|
151
|
+
*
|
|
152
|
+
* Normalising to strings here is what keeps boolean-axis handling in a single
|
|
153
|
+
* place: `true` becomes `"true"`, and every lookup downstream — variant
|
|
154
|
+
* classes and compound matching alike — is a plain string compare.
|
|
155
|
+
*/
|
|
156
|
+
function toValueMap(source: object | undefined): Record<string, string> {
|
|
157
|
+
const out: Record<string, string> = {};
|
|
158
|
+
if (!source) return out;
|
|
159
|
+
for (const [key, value] of entriesOf(source)) {
|
|
160
|
+
if (isClassKey(key)) continue;
|
|
161
|
+
if (value === undefined || value === null) continue;
|
|
162
|
+
out[key] = String(value);
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Merge caller props over the defaults.
|
|
169
|
+
*
|
|
170
|
+
* An omitted axis (or an explicit `undefined`) keeps its default; an explicit
|
|
171
|
+
* `null` clears it, which is how upstream cva lets a caller opt out of a
|
|
172
|
+
* default variant entirely.
|
|
173
|
+
*/
|
|
174
|
+
function selectionFor(
|
|
175
|
+
defaults: Record<string, string>,
|
|
176
|
+
props: object | undefined,
|
|
177
|
+
): Record<string, string | undefined> {
|
|
178
|
+
const selection: Record<string, string | undefined> = { ...defaults };
|
|
179
|
+
if (!props) return selection;
|
|
180
|
+
|
|
181
|
+
for (const [key, value] of entriesOf(props)) {
|
|
182
|
+
if (isClassKey(key)) continue;
|
|
183
|
+
if (value === undefined) continue;
|
|
184
|
+
selection[key] = value === null ? undefined : String(value);
|
|
185
|
+
}
|
|
186
|
+
return selection;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Flatten compound rules once, at construction, rather than on every call. */
|
|
190
|
+
function normaliseCompounds<V extends VariantShape>(
|
|
191
|
+
compounds: ReadonlyArray<CompoundVariant<V>> | undefined,
|
|
192
|
+
): readonly CompoundRule[] {
|
|
193
|
+
if (!compounds) return [];
|
|
194
|
+
|
|
195
|
+
const out: CompoundRule[] = [];
|
|
196
|
+
for (const rule of compounds) {
|
|
197
|
+
const conditions: Array<readonly [string, readonly string[]]> = [];
|
|
198
|
+
const classes: ClassValue[] = [];
|
|
199
|
+
|
|
200
|
+
for (const [key, value] of entriesOf(rule)) {
|
|
201
|
+
if (isClassKey(key)) {
|
|
202
|
+
if (isClassValue(value)) classes.push(value);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (value === undefined || value === null) continue;
|
|
206
|
+
const accepted = Array.isArray(value)
|
|
207
|
+
? value.map((one) => String(one))
|
|
208
|
+
: [String(value)];
|
|
209
|
+
conditions.push([key, accepted]);
|
|
210
|
+
}
|
|
211
|
+
out.push({ conditions, classes });
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Does every condition of a compound rule hold for this selection? */
|
|
217
|
+
function satisfies(
|
|
218
|
+
rule: CompoundRule,
|
|
219
|
+
selection: Record<string, string | undefined>,
|
|
220
|
+
): boolean {
|
|
221
|
+
for (const [axis, accepted] of rule.conditions) {
|
|
222
|
+
const actual = selection[axis];
|
|
223
|
+
if (actual === undefined) return false;
|
|
224
|
+
if (!accepted.includes(actual)) return false;
|
|
225
|
+
}
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function isClassKey(key: string): boolean {
|
|
230
|
+
return key === "class" || key === "className";
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Narrow a compound rule's `class` / `className` back to `ClassValue`.
|
|
235
|
+
*
|
|
236
|
+
* The value arrives as `unknown` from `entriesOf`; `ClassValue` covers every
|
|
237
|
+
* shape `cn` accepts, so anything that is not a rejected primitive passes
|
|
238
|
+
* through untouched and `cn` does the rest of the work.
|
|
239
|
+
*/
|
|
240
|
+
function isClassValue(value: unknown): value is ClassValue {
|
|
241
|
+
return (
|
|
242
|
+
typeof value === "string" ||
|
|
243
|
+
typeof value === "number" ||
|
|
244
|
+
typeof value === "boolean" ||
|
|
245
|
+
value === null ||
|
|
246
|
+
value === undefined ||
|
|
247
|
+
typeof value === "object"
|
|
248
|
+
);
|
|
249
|
+
}
|
package/src/lib/icons.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline icons.
|
|
3
|
+
*
|
|
4
|
+
* shadcn/ui pulls every glyph from `lucide-react`. nebula cannot: it is a
|
|
5
|
+
* React package, and taking a dependency for fifteen paths would undo the
|
|
6
|
+
* point of writing `cn` and `cva` by hand.
|
|
7
|
+
*
|
|
8
|
+
* So the glyphs the component set actually needs are inlined here, traced from
|
|
9
|
+
* Lucide's own 24×24 grid so they sit correctly next to Lucide icons in an app
|
|
10
|
+
* that also uses the real thing. Nothing else is added — this is not an icon
|
|
11
|
+
* library, and an app wanting a hundred more should install one and pass the
|
|
12
|
+
* markup in as content.
|
|
13
|
+
*
|
|
14
|
+
* `currentColor` throughout and no hardcoded size: an icon inherits the text
|
|
15
|
+
* colour of whatever it sits in, and the `[&_svg]:size-4` rules on Button and
|
|
16
|
+
* friends set the size from the component. That is what lets the same icon
|
|
17
|
+
* work in a button, a menu item and a badge without a variant each.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { html, type TemplateResult } from "@c9up/aurora";
|
|
21
|
+
|
|
22
|
+
export interface IconProps {
|
|
23
|
+
class?: string;
|
|
24
|
+
/** Icons are decorative by default; give a label to expose one to a reader. */
|
|
25
|
+
label?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Wrap path data in a Lucide-shaped `<svg>`.
|
|
30
|
+
*
|
|
31
|
+
* `aria-hidden` unless labelled, because an icon beside its own text label is
|
|
32
|
+
* noise to a screen reader — it reads the glyph's name and then the text. The
|
|
33
|
+
* exceptions are icon-only controls, which pass a label.
|
|
34
|
+
*/
|
|
35
|
+
function svg(body: TemplateResult, props: IconProps = {}): TemplateResult {
|
|
36
|
+
return html`<svg
|
|
37
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
38
|
+
viewBox="0 0 24 24"
|
|
39
|
+
fill="none"
|
|
40
|
+
stroke="currentColor"
|
|
41
|
+
stroke-width="2"
|
|
42
|
+
stroke-linecap="round"
|
|
43
|
+
stroke-linejoin="round"
|
|
44
|
+
class="${props.class}"
|
|
45
|
+
aria-hidden="${props.label === undefined ? "true" : undefined}"
|
|
46
|
+
aria-label="${props.label}"
|
|
47
|
+
role="${props.label === undefined ? undefined : "img"}"
|
|
48
|
+
>${body}</svg>`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const CheckIcon = (props?: IconProps): TemplateResult =>
|
|
52
|
+
svg(html`<path d="M20 6 9 17l-5-5" />`, props);
|
|
53
|
+
|
|
54
|
+
export const MinusIcon = (props?: IconProps): TemplateResult =>
|
|
55
|
+
svg(html`<path d="M5 12h14" />`, props);
|
|
56
|
+
|
|
57
|
+
export const XIcon = (props?: IconProps): TemplateResult =>
|
|
58
|
+
svg(html`<path d="M18 6 6 18" /><path d="m6 6 12 12" />`, props);
|
|
59
|
+
|
|
60
|
+
export const ChevronDownIcon = (props?: IconProps): TemplateResult =>
|
|
61
|
+
svg(html`<path d="m6 9 6 6 6-6" />`, props);
|
|
62
|
+
|
|
63
|
+
export const ChevronUpIcon = (props?: IconProps): TemplateResult =>
|
|
64
|
+
svg(html`<path d="m18 15-6-6-6 6" />`, props);
|
|
65
|
+
|
|
66
|
+
export const ChevronLeftIcon = (props?: IconProps): TemplateResult =>
|
|
67
|
+
svg(html`<path d="m15 18-6-6 6-6" />`, props);
|
|
68
|
+
|
|
69
|
+
export const ChevronRightIcon = (props?: IconProps): TemplateResult =>
|
|
70
|
+
svg(html`<path d="m9 18 6-6-6-6" />`, props);
|
|
71
|
+
|
|
72
|
+
export const ChevronsUpDownIcon = (props?: IconProps): TemplateResult =>
|
|
73
|
+
svg(html`<path d="m7 15 5 5 5-5" /><path d="m7 9 5-5 5 5" />`, props);
|
|
74
|
+
|
|
75
|
+
export const SearchIcon = (props?: IconProps): TemplateResult =>
|
|
76
|
+
svg(html`<circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" />`, props);
|
|
77
|
+
|
|
78
|
+
export const CircleIcon = (props?: IconProps): TemplateResult =>
|
|
79
|
+
svg(html`<circle cx="12" cy="12" r="10" />`, props);
|
|
80
|
+
|
|
81
|
+
/** Filled dot — the selected marker inside a radio. */
|
|
82
|
+
export const DotIcon = (props?: IconProps): TemplateResult =>
|
|
83
|
+
svg(
|
|
84
|
+
html`<circle cx="12" cy="12" r="4" fill="currentColor" stroke="none" />`,
|
|
85
|
+
props,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
export const MoreHorizontalIcon = (props?: IconProps): TemplateResult =>
|
|
89
|
+
svg(
|
|
90
|
+
html`<circle cx="12" cy="12" r="1" /><circle cx="19" cy="12" r="1" /><circle
|
|
91
|
+
cx="5"
|
|
92
|
+
cy="12"
|
|
93
|
+
r="1"
|
|
94
|
+
/>`,
|
|
95
|
+
props,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
export const ArrowLeftIcon = (props?: IconProps): TemplateResult =>
|
|
99
|
+
svg(html`<path d="m12 19-7-7 7-7" /><path d="M19 12H5" />`, props);
|
|
100
|
+
|
|
101
|
+
export const ArrowRightIcon = (props?: IconProps): TemplateResult =>
|
|
102
|
+
svg(html`<path d="M5 12h14" /><path d="m12 5 7 7-7 7" />`, props);
|
|
103
|
+
|
|
104
|
+
export const CalendarIcon = (props?: IconProps): TemplateResult =>
|
|
105
|
+
svg(
|
|
106
|
+
html`<path d="M8 2v4" /><path d="M16 2v4" /><rect
|
|
107
|
+
width="18"
|
|
108
|
+
height="18"
|
|
109
|
+
x="3"
|
|
110
|
+
y="4"
|
|
111
|
+
rx="2"
|
|
112
|
+
/><path d="M3 10h18" />`,
|
|
113
|
+
props,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
export const PanelLeftIcon = (props?: IconProps): TemplateResult =>
|
|
117
|
+
svg(
|
|
118
|
+
html`<rect width="18" height="18" x="3" y="3" rx="2" /><path d="M9 3v18" />`,
|
|
119
|
+
props,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
export const GripVerticalIcon = (props?: IconProps): TemplateResult =>
|
|
123
|
+
svg(
|
|
124
|
+
html`<circle cx="9" cy="12" r="1" /><circle cx="9" cy="5" r="1" /><circle
|
|
125
|
+
cx="9"
|
|
126
|
+
cy="19"
|
|
127
|
+
r="1"
|
|
128
|
+
/><circle cx="15" cy="12" r="1" /><circle cx="15" cy="5" r="1" /><circle
|
|
129
|
+
cx="15"
|
|
130
|
+
cy="19"
|
|
131
|
+
r="1"
|
|
132
|
+
/>`,
|
|
133
|
+
props,
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
/** The arc Lucide uses for `loader-circle`; spun by the Spinner's animation. */
|
|
137
|
+
export const LoaderIcon = (props?: IconProps): TemplateResult =>
|
|
138
|
+
svg(html`<path d="M21 12a9 9 0 1 1-6.219-8.56" />`, props);
|
package/src/lib/id.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
|
|
21
|
+
let counter = 0;
|
|
22
|
+
|
|
23
|
+
/** Mint an id unique within this render pass. */
|
|
24
|
+
export function uid(prefix = "nebula"): string {
|
|
25
|
+
counter += 1;
|
|
26
|
+
return `${prefix}-${counter}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Restart the sequence. Call once per SSR render, before building the tree. */
|
|
30
|
+
export function resetIds(): void {
|
|
31
|
+
counter = 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Look an element up by the id a component minted for it.
|
|
36
|
+
*
|
|
37
|
+
* Returns `null` off the DOM (SSR) or before mount rather than throwing, so
|
|
38
|
+
* callers can run the same code in both environments. Every consumer inside
|
|
39
|
+
* nebula is in `onMount`, where the node is live.
|
|
40
|
+
*/
|
|
41
|
+
export function byId(id: string): HTMLElement | null {
|
|
42
|
+
if (typeof document === "undefined") return null;
|
|
43
|
+
return document.getElementById(id);
|
|
44
|
+
}
|
package/src/lib/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
|
|
10
|
+
export { type ClassValue, clsx, cn, twMerge } from "./cn.js";
|
|
11
|
+
export {
|
|
12
|
+
type ClassOverrides,
|
|
13
|
+
type CompoundVariant,
|
|
14
|
+
cva,
|
|
15
|
+
type VariantConfig,
|
|
16
|
+
type VariantProps,
|
|
17
|
+
type VariantSelection,
|
|
18
|
+
type VariantShape,
|
|
19
|
+
} from "./cva.js";
|
|
20
|
+
export { byId, resetIds, uid } from "./id.js";
|
|
21
|
+
export { accessor, callHandler, type Reactive, read, readOr } from "./props.js";
|