@cloudwick/astral-ui-cli 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.
@@ -0,0 +1,3 @@
1
+ export { keyboardKeys } from "./keyboardKey";
2
+
3
+ export const mobileBreakPoint = 767;
@@ -0,0 +1,16 @@
1
+ export const keyboardKeys = {
2
+ arrowUp: "ArrowUp",
3
+ arrowDown: "ArrowDown",
4
+ arrowLeft: "ArrowLeft",
5
+ arrowRight: "ArrowRight",
6
+ enter: "Enter",
7
+ escape: "Escape",
8
+ end: "End",
9
+ home: "Home",
10
+ backspace: "Backspace",
11
+ tab: "Tab",
12
+ v: "v",
13
+ delete: "Delete",
14
+ pageUp: "PageUp",
15
+ pageDown: "PageDown"
16
+ };
@@ -0,0 +1,82 @@
1
+ /* This file is auto-generated. Do not edit directly. */
2
+ /* It is updated whenever the component library is built. */
3
+
4
+ @layer base {
5
+ :root {
6
+ /* Color: rgb(x y z) */
7
+ --iridium: 24 24 24;
8
+ --frost-blue: 244 247 250;
9
+
10
+ /* Primary colors (Shades of Blue) */
11
+ --primary-50: 233 247 254;
12
+ --primary-100: 205 235 254;
13
+ --primary-200: 166 221 253;
14
+ --primary-300: 106 200 251;
15
+ --primary-400: 36 167 249;
16
+ --primary-500: 6 118 215;
17
+ --primary-600: 6 92 197;
18
+ --primary-700: 5 74 189;
19
+ --primary-800: 9 64 164;
20
+ --primary-900: 13 52 118;
21
+
22
+ /* Secondary colors (Shades of Gray) */
23
+ --secondary-50: 242 243 246;
24
+ --secondary-100: 229 230 235;
25
+ --secondary-200: 195 200 211;
26
+ --secondary-300: 143 154 173;
27
+ --secondary-400: 89 100 121;
28
+ --secondary-500: 57 64 77;
29
+ --secondary-600: 46 52 63;
30
+ --secondary-700: 37 42 52;
31
+ --secondary-800: 31 35 42;
32
+ --secondary-900: 29 31 37;
33
+
34
+ /* Warning colors (Shades of Yellow) */
35
+ --warning-50: 254 250 238;
36
+ --warning-100: 254 241 204;
37
+ --warning-200: 253 226 147;
38
+ --warning-300: 251 207 93;
39
+ --warning-400: 250 182 46;
40
+ --warning-500: 245 154 32;
41
+ --warning-600: 234 117 7;
42
+ --warning-700: 194 81 10;
43
+ --warning-800: 158 62 15;
44
+ --warning-900: 129 51 17;
45
+
46
+ /* Success Colors (Shades of Green) */
47
+ --success-50: 242 251 245;
48
+ --success-100: 225 244 230;
49
+ --success-200: 198 232 209;
50
+ --success-300: 160 215 181;
51
+ --success-400: 101 180 134;
52
+ --success-500: 61 180 115;
53
+ --success-600: 40 145 90;
54
+ --success-700: 33 116 74;
55
+ --success-800: 28 93 60;
56
+ --success-900: 24 77 52;
57
+
58
+ /* Error colors (Shades of Red) */
59
+ --error-50: 254 243 242;
60
+ --error-100: 253 229 227;
61
+ --error-200: 252 208 204;
62
+ --error-300: 249 175 168;
63
+ --error-400: 243 129 118;
64
+ --error-500: 231 73 58;
65
+ --error-600: 214 59 44;
66
+ --error-700: 179 47 34;
67
+ --error-800: 149 41 31;
68
+ --error-900: 124 40 32;
69
+
70
+ /* Gray colors (Shades of Ligh Gray) */
71
+ --gray-50: 245 246 247;
72
+ --gray-100: 234 236 240;
73
+ --gray-200: 214 218 225;
74
+ --gray-300: 193 199 209;
75
+ --gray-400: 173 181 194;
76
+ --gray-500: 152 162 179;
77
+ --gray-600: 142 153 170;
78
+ --gray-700: 128 139 156;
79
+ --gray-800: 117 129 149;
80
+ --gray-900: 95 105 120;
81
+ }
82
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "Astral-UI ComponentsConfig",
4
+ "type": "object",
5
+ "properties": {
6
+ "$schema": {
7
+ "type": "string"
8
+ },
9
+ "tailwind": {
10
+ "type": "object",
11
+ "properties": {
12
+ "config": {
13
+ "type": "string"
14
+ },
15
+ "css": {
16
+ "type": "string"
17
+ }
18
+ },
19
+ "required": [
20
+ "config",
21
+ "css"
22
+ ]
23
+ },
24
+ "aliases": {
25
+ "type": "object",
26
+ "properties": {
27
+ "components": {
28
+ "type": "string"
29
+ },
30
+ "utils": {
31
+ "type": "string"
32
+ },
33
+ "constants": {
34
+ "type": "string"
35
+ }
36
+ },
37
+ "required": [
38
+ "components",
39
+ "utils",
40
+ "constants"
41
+ ]
42
+ },
43
+ "extensions": {
44
+ "type": "array",
45
+ "items": {
46
+ "type": "string"
47
+ }
48
+ }
49
+ },
50
+ "required": [
51
+ "$schema",
52
+ "tailwind",
53
+ "aliases",
54
+ "extensions"
55
+ ]
56
+ }
@@ -0,0 +1,13 @@
1
+ import { clsx, type ClassValue } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ /**
5
+ * Merges multiple class values into a single className string
6
+ * Uses clsx for conditional classes and twMerge to handle Tailwind conflicts
7
+ * @param inputs - Class values to merge
8
+ * @returns Merged className string
9
+ * @example cn("text-red-500", "bg-blue-500", isActive && "font-bold")
10
+ */
11
+ export function cn( ...inputs: ClassValue[]) {
12
+ return twMerge( clsx( inputs ));
13
+ }
@@ -0,0 +1,33 @@
1
+ // eslint disabled on entire file because we don't want to enforce prop types
2
+ // this is a utility function that should be used in a component that already has prop types
3
+ // and we don't want to force prop types on this utility function
4
+ /* eslint-disable @typescript-eslint/no-explicit-any */
5
+
6
+ /**
7
+ * Debounce a function, making it only callable after a certain amount of time has passed.
8
+ * @param func The function to debounce.
9
+ * @param timeout The amount of time to wait before calling the function.
10
+ * @returns A debounced version of the function.
11
+ * @template Params The parameters of the function.
12
+ * @example
13
+ * ```tsx
14
+ * const debouncedFunction = debounce((...args) => {
15
+ * console.log(args);
16
+ * }, 1000);
17
+ * debouncedFunction(1);
18
+ * ```
19
+ */
20
+ export function debounce<Params extends any[]>(
21
+ func: ( ...args: Params ) => any,
22
+ timeout: number
23
+ ): ( ...args: Params ) => void {
24
+ let timer: NodeJS.Timeout;
25
+ return ( ...args: Params ) => {
26
+ if ( timer ) {
27
+ clearTimeout( timer );
28
+ }
29
+ timer = setTimeout(() => {
30
+ func( ...args );
31
+ }, timeout );
32
+ };
33
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Finds the closest parent element of the given element that has the specified attribute set,
3
+ * and returns the value of that attribute.
4
+ *
5
+ * @param {HTMLElement} element - The starting element to search from.
6
+ * @param {string} attribute - The attribute to search for.
7
+ * @returns {string | null} The value of the specified attribute on the closest parent element that has it set, or null if no such parent element is found.
8
+ */
9
+ export const findParentAttribute = ( element: HTMLElement, attribute:string ): string | null => {
10
+ if ( !element ) {
11
+ return null;
12
+ }
13
+ let { parentElement } = element;
14
+ while ( parentElement ) {
15
+ const dir = parentElement.getAttribute( attribute );
16
+ if ( dir ) {
17
+ return dir;
18
+ }
19
+ parentElement = parentElement?.parentElement;
20
+ }
21
+
22
+ return null;
23
+ };
@@ -0,0 +1,38 @@
1
+ // disable eslint on entire file because we don't want to enforce prop types,
2
+ // this is a utility function that should be used in a component that already has prop types
3
+ // and we don't want to force prop types on this utility function
4
+ /* eslint-disable */
5
+
6
+ /**
7
+ * Returns a createElement() type based on the props of the Component.
8
+ * Useful for calculating what type a component should render as.
9
+ *
10
+ * @param {function} Component A function or ReactClass.
11
+ * @param {object} props A ReactElement props object
12
+ * @param {function} [getDefault] A function that returns a default element type.
13
+ * @returns {string|function} A ReactElement type
14
+ */
15
+ function getElementType(
16
+ Component: React.ComponentType<any>, componentProps: { [key: string]: any },
17
+ getDefault?: () => any ): string | React.ComponentType<any> {
18
+ const { defaultProps = {} } = Component;
19
+
20
+ // user defined "as" element type
21
+ if ( componentProps.as && componentProps.as !== defaultProps.as ) {
22
+ return componentProps.as;
23
+ }
24
+
25
+ // get computed default element type
26
+ if ( getDefault ) {
27
+ const defaultAs = getDefault();
28
+ if ( defaultAs ) {
29
+ return defaultAs;
30
+ }
31
+ }
32
+
33
+ // use defaultProps.as or 'div'
34
+ return defaultProps.as || "div";
35
+ }
36
+ /* eslint-enable */
37
+
38
+ export default getElementType;
@@ -0,0 +1,7 @@
1
+ export * from "./numberUtils";
2
+ export * from "./stringUtils";
3
+ export { useOnScreen } from "./useOnScreen";
4
+ export { debounce } from "./debounce";
5
+ export { useWindowSize } from "./useWindowSize";
6
+ export * from "./findParentAttribute";
7
+ export { cn } from "./cn";
@@ -0,0 +1,40 @@
1
+ /**
2
+ * This method accepts a number and returns a string representation
3
+ * of the number formatted/abbreviated to the closest higher precision value.
4
+ * @param {number} value - The value to be formatted
5
+ * @param {number} precision - The default precision to be used for output
6
+ * @param {boolean} prefixZero - Flag to prepend zero to the output if result is a single digit number
7
+ * @returns {string} - The formatted/abbreviated string
8
+ * @example <caption>Example usage of abbreviateNumber method.</caption>
9
+ * // returns 12.1M
10
+ * abbreviateNumber(12093093, 3);
11
+ */
12
+ export const abbreviateNumber = ( value = 0, precision = 1, prefixZero = true ): string => {
13
+ const adjustedPrecision = isNaN( precision ) ? 1 : precision;
14
+ const adjustedValue = isNaN( value ) ? 0 : parseFloat( `${value}` );
15
+ const isNegativeValue = adjustedValue < 0;
16
+ const absoluteValue = isNegativeValue ? Math.abs( adjustedValue ) : value;
17
+ let returnValue = absoluteValue.toFixed( adjustedPrecision );
18
+ if ( absoluteValue >= 1000 ) {
19
+ const suffixes = [ "", "K", "M", "B", "T", "P", "E", "Z", "Y" ];
20
+ const suffixNum = Math.floor(( `${absoluteValue}` ).length / 3 );
21
+ let shortValue: number = absoluteValue;
22
+ for ( let precisionCounter = adjustedPrecision; precisionCounter >= 1; precisionCounter-- ) {
23
+ shortValue = parseFloat(( suffixNum !== 0
24
+ ? ( absoluteValue / Math.pow( 1000, suffixNum ))
25
+ : absoluteValue ).toPrecision( precisionCounter )
26
+ );
27
+ const dotLessShortValue = ( `${shortValue}` ).replace( /[^a-zA-Z 0-9]+/g, "" );
28
+ if ( dotLessShortValue.length <= adjustedPrecision ) {
29
+ break;
30
+ }
31
+ }
32
+ if ( shortValue % 1 !== 0 ) {
33
+ shortValue = parseFloat( shortValue.toFixed( adjustedPrecision ));
34
+ }
35
+ returnValue = shortValue + suffixes[suffixNum];
36
+ } else {
37
+ returnValue = `${( prefixZero && absoluteValue < 10 ) ? "0" : ""}${ parseFloat( returnValue )}`;
38
+ }
39
+ return `${isNegativeValue ? "-" : ""}${returnValue}`;
40
+ };
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ /**
3
+ * Function to convert file size in bytes to human readable format
4
+ * @param size - size of the file in bytes
5
+ * @returns {string} - human readable file size
6
+ * @example <caption>Example usage of readableFileSize</caption>
7
+ * readableFileSize(1024) // returns '1 kB'
8
+ * readableFileSize(1024 * 1024 * 1024) // returns '1 GB'
9
+ */
10
+ export function readableFileSize( size: number ): string {
11
+ const i = size !== 0 ? Math.floor( Math.log( size ) / Math.log( 1024 )) : 0;
12
+ return `${Number(( size / Math.pow( 1024, i )).toFixed( 2 )) } ${ [ "B", "kB", "MB", "GB", "TB" ][i]}`;
13
+ }
@@ -0,0 +1,22 @@
1
+ import React, { ReactElement } from "react";
2
+ /**
3
+ * This method accepts a string and returns a string representation
4
+ * of the value shrunk to 2 characters representing the Initials.
5
+ * @param {string} value - The value to be converted to Initials
6
+ * @returns {string} - The 2character string of the initials extracted from the given value string.
7
+ * @example <caption>Example usage of getInitials method.</caption>
8
+ * // returns SP
9
+ * getInitials('Susheel Pogaku');
10
+ */
11
+ export const getInitials = ( value:string ): string => {
12
+ return value
13
+ ?.match( /(^\S\S?|\b\S)?/g )?.join( "" )
14
+ ?.match( /(^\S|\S$)?/g )?.join( "" )
15
+ ?.toUpperCase() ?? "AU";
16
+ };
17
+
18
+ export const GetInitials = ( value:string ): ReactElement => {
19
+ return <React.Fragment>
20
+ {getInitials( value )}
21
+ </React.Fragment>;
22
+ };
@@ -0,0 +1,4 @@
1
+ export * from "./getInitials";
2
+ export { PlaceholderText } from "./placeholderText";
3
+ export { regexSearch } from "./regexSearch";
4
+ export { readableFileSize } from "./fileSize";
@@ -0,0 +1,93 @@
1
+ import React, { ReactElement } from "react";
2
+
3
+ type Variant = "lorem" | "space" | "startrek";
4
+
5
+ export interface PlaceholderTextProps {
6
+ paragraphs?: number;
7
+ sentences?: number;
8
+ variant?: Variant;
9
+ }
10
+
11
+ const getRandomSentences = (
12
+ source: string[],
13
+ sentences: number
14
+ ): string => {
15
+ const result = new Array( sentences );
16
+ let sourceLength = source.length;
17
+ const taken = new Array( sourceLength );
18
+ if ( sentences <= sourceLength ) {
19
+ while ( sentences-- ) {
20
+ const x = Math.floor( Math.random() * sourceLength );
21
+ result[sentences] = source[x in taken ? taken[x] : x];
22
+ taken[x] = --sourceLength in taken ? taken[sourceLength] : sourceLength;
23
+ }
24
+ }
25
+ return result.join( " " ).replace( /\s+/g, " " ).trim();
26
+ };
27
+
28
+ export const placeholderText = ( sentences:number, variant: Variant = "lorem" as Variant ): string => {
29
+ const wordCollection = variants?.[variant] ?? variants.lorem;
30
+ const paragraph = getRandomSentences( wordCollection, sentences );
31
+ return paragraph;
32
+ };
33
+
34
+ export const PlaceholderText = ({
35
+ paragraphs = 2,
36
+ sentences = 4,
37
+ variant = "lorem"
38
+ }: PlaceholderTextProps ): ReactElement => {
39
+ let text = "";
40
+ for ( let i = 0; i < paragraphs; i++ ){
41
+ const paragraph = `<p>${placeholderText( sentences, variant )}</p>`;
42
+ text += paragraph;
43
+ }
44
+ return <div className="space-y-2 text-start dark:text-secondary-200" dangerouslySetInnerHTML={{ __html: text }}></div>;
45
+ };
46
+
47
+ export default PlaceholderText;
48
+
49
+ const variants = {
50
+ "lorem": [
51
+ "Lorem ipsum dolor sit amet , consectetur adipiscing",
52
+ "elit sed do eiusmod tempor incididunt ut labore",
53
+ "et dolore magna aliqua. Ut enim ad minim veniam, ",
54
+ "quis nostrud exercitation ullamco laboris nisi ut",
55
+ "aliquip ex ea commodo consequat Duis aute irure",
56
+ "dolor in reprehenderit in voluptate velit esse cillum",
57
+ "dolore eu fugiat nulla pariatur Excepteur sint,",
58
+ "occaecat cupidatat non proident sunt in culpa qui",
59
+ "aliquip ex ea commodo consequat Duis aute irure",
60
+ "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet",
61
+ "elit sed do eiusmod tempor incididunt ut labore",
62
+ "officia deserunt mollit anim id est laborum"
63
+ ],
64
+ "space": [
65
+ "There is no atmosphere in space and sound cannot travel without a medium.",
66
+ "Mercury is closest planet to sun, but venus is the hottest planet in solar system.",
67
+ "There are between 100-400 billion stars, approximately, in the galaxy.",
68
+ "There is a planet made of diamonds twice the size of earth.",
69
+ "One teaspoonful of neutron star would weigh the same as the entire human population.",
70
+ "In fact, cosmic expansion is actually accelerating.",
71
+ "Black holes are known for their voracious appetites;",
72
+ "Neptune only recently finished its first full post-discovery orbit in 2011.",
73
+ "Not all planets form and stay around stars.",
74
+ "We are all made of stardust. It sounds like a line from a poem.",
75
+ "It takes 230 million years for our solar system to complete one single orbit around the Milky Way.",
76
+ "Polaris, our North Star, is not leaving us anytime soon."
77
+ ],
78
+ "startrek": [
79
+ "There are four lights!",
80
+ "Things are only impossible until they are not!",
81
+ "Sokath, his eyes uncovered! Captain Picard is stuck on planet.",
82
+ "Logic is the beginning of wisdom, not the end.",
83
+ "Live long, and prosper.",
84
+ "Resistance is futile.",
85
+ "It is possible to commit no errors and still lose, that is not a weakness, that is life.",
86
+ "Without freedom of choice there is no creativity.",
87
+ "You can use logic to justify almost anything. That's its power. And its flaw.",
88
+ "Mr. Data, set heading to Alpha Quadrant, maximum warp, Engage !",
89
+ "Change is the essential process of all existence.",
90
+ "Insufficient facts always invite danger.",
91
+ "What does God need with a starship."
92
+ ]
93
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Function to verify if a string exists within another string using regex
3
+ *
4
+ * @param {string} stringToSearchFor
5
+ * @param {string} stringToSearchIn
6
+ * @param {boolean} caseSensitive (optional) default false
7
+ * @returns {boolean} True if the stringToSearchFor is found, false otherwise.
8
+ */
9
+
10
+ export const regexSearch = (
11
+ stringToSearchFor: string,
12
+ stringToSearchIn: string,
13
+ caseSensitive = false
14
+ ): boolean => {
15
+ if ( !stringToSearchFor ){
16
+ return true;
17
+ }
18
+ if ( !stringToSearchIn ) {
19
+ return false;
20
+ }
21
+
22
+ try {
23
+ const regex = new RegExp( stringToSearchFor, caseSensitive ? "g" : "gi" );
24
+ return regex.test( stringToSearchIn );
25
+ } catch ( error: unknown ) {
26
+ console.error( "Invalid regular expression:", ( error as Error )?.message );
27
+ return false;
28
+ }
29
+ };
@@ -0,0 +1,22 @@
1
+ import { useEffect, useState, useMemo } from "react";
2
+
3
+ export function useOnScreen( ref: React.RefObject<Element> ): boolean {
4
+
5
+ const [ isIntersecting, setIntersecting ] = useState<boolean>( false );
6
+
7
+ const observer = useMemo(() => new IntersectionObserver(
8
+ ([entry]) => setIntersecting( entry.isIntersecting )
9
+ ), []);
10
+
11
+ useEffect(() => {
12
+ if ( ref.current ) {
13
+ observer.observe( ref.current );
14
+ }
15
+ // Remove the observer as soon as the component is unmounted
16
+ return () => {
17
+ observer.disconnect();
18
+ };
19
+ }, [ ref, observer ]);
20
+
21
+ return isIntersecting;
22
+ }
@@ -0,0 +1,33 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ type ReturnType = {
4
+ width: number;
5
+ height: number;
6
+ };
7
+
8
+ export function useWindowSize(): ReturnType {
9
+ const [ windowSize, setWindowSize ] = useState<{
10
+ width: number | undefined;
11
+ height: number | undefined;
12
+ }>({
13
+ width: undefined,
14
+ height: undefined
15
+ });
16
+ useEffect(() => {
17
+ // Handler to call on window resize
18
+ function handleResize() {
19
+ // Set window width/height to state
20
+ setWindowSize({
21
+ width: window.innerWidth,
22
+ height: window.innerHeight
23
+ });
24
+ }
25
+ // Add event listener
26
+ window.addEventListener( "resize", handleResize );
27
+ // Call handler right away so state gets updated with initial window size
28
+ handleResize();
29
+ // Remove event listener on cleanup
30
+ return () => window.removeEventListener( "resize", handleResize );
31
+ }, []); // Empty array ensures that effect is only run on mount
32
+ return windowSize as ReturnType;
33
+ }
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@cloudwick/astral-ui-cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI for installing Astral UI components in any codebase",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "astral-ui": "./dist/index.js"
8
+ },
9
+ "type": "commonjs",
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "dev": "tsup --watch",
17
+ "test": "vitest run",
18
+ "lint:js": "eslint \"src/**/*.ts\"",
19
+ "lint": "yarn lint:js",
20
+ "lint:fix": "eslint \"src/**/*.ts\" --fix",
21
+ "prepublishOnly": "yarn build"
22
+ },
23
+ "keywords": [
24
+ "astral",
25
+ "ui",
26
+ "components",
27
+ "cli",
28
+ "react"
29
+ ],
30
+ "author": "Cloudwick Technologies",
31
+ "license": "MIT",
32
+ "devDependencies": {
33
+ "@types/chalk-animation": "^1.6.1",
34
+ "@types/fs-extra": "^11.0.4",
35
+ "@types/gradient-string": "^1.1.2",
36
+ "@types/inquirer": "^9.0.3",
37
+ "@types/node": "^20.10.6",
38
+ "@types/prompts": "^2.4.9",
39
+ "@types/semver": "^7.5.6",
40
+ "@typescript-eslint/eslint-plugin": "^6.12.0",
41
+ "@typescript-eslint/parser": "^6.12.0",
42
+ "eslint": "^8.54.0",
43
+ "tsup": "^8.0.1",
44
+ "typescript": "^5.3.3",
45
+ "vitest": "^1.1.1"
46
+ },
47
+ "dependencies": {
48
+ "@cloudwick/astral-config": "workspace:*",
49
+ "@cloudwick/astral-ui": "workspace:*",
50
+ "chalk": "^4.1.2",
51
+ "chalk-animation": "^2.0.3",
52
+ "commander": "^11.1.0",
53
+ "execa": "^5.1.1",
54
+ "fs-extra": "^11.2.0",
55
+ "gradient-string": "^1.2.0",
56
+ "inquirer": "^8.2.5",
57
+ "ora": "^5.4.1",
58
+ "prompts": "^2.4.2",
59
+ "semver": "^7.5.4",
60
+ "zod": "^3.22.4"
61
+ },
62
+ "engines": {
63
+ "node": ">=18.0.0"
64
+ }
65
+ }