@codav/slug-generator 1.0.2 → 1.0.4
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/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +29 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +29 -63
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -16,6 +16,6 @@ type SlugGeneratorProps = {
|
|
|
16
16
|
transliteratePersian?: boolean;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
declare function SlugGenerator({ title, value, onChange, label, placeholder, buttonText, disabled, className, icon, dir,
|
|
19
|
+
declare function SlugGenerator({ title, value, onChange, label, placeholder, buttonText, disabled, className, icon, dir, transliteratePersian, }: SlugGeneratorProps): react.JSX.Element;
|
|
20
20
|
|
|
21
21
|
export { SlugGenerator, type SlugGeneratorProps };
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,6 @@ type SlugGeneratorProps = {
|
|
|
16
16
|
transliteratePersian?: boolean;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
declare function SlugGenerator({ title, value, onChange, label, placeholder, buttonText, disabled, className, icon, dir,
|
|
19
|
+
declare function SlugGenerator({ title, value, onChange, label, placeholder, buttonText, disabled, className, icon, dir, transliteratePersian, }: SlugGeneratorProps): react.JSX.Element;
|
|
20
20
|
|
|
21
21
|
export { SlugGenerator, type SlugGeneratorProps };
|
package/dist/index.js
CHANGED
|
@@ -83,12 +83,12 @@ var ARABIC_DIACRITICS = /[\u064B-\u065F\u0670]/g;
|
|
|
83
83
|
function transliterate(text) {
|
|
84
84
|
return text.normalize("NFKC").replace(ARABIC_DIACRITICS, "").split("").map((char) => PERSIAN_MAP[char] ?? char).join("");
|
|
85
85
|
}
|
|
86
|
-
function
|
|
86
|
+
function createSlug(title, transliteratePersian = true) {
|
|
87
87
|
let source = title.normalize("NFKC").replace(ARABIC_DIACRITICS, "");
|
|
88
88
|
if (transliteratePersian) {
|
|
89
89
|
source = transliterate(source);
|
|
90
90
|
}
|
|
91
|
-
return source.toLowerCase().trim().replace(/['’`"]/g, "").replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(
|
|
91
|
+
return source.toLowerCase().trim().replace(/['’`"]/g, "").replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
92
92
|
}
|
|
93
93
|
function SlugGenerator({
|
|
94
94
|
title,
|
|
@@ -98,44 +98,21 @@ function SlugGenerator({
|
|
|
98
98
|
placeholder = "your-slug",
|
|
99
99
|
buttonText = "Generate",
|
|
100
100
|
disabled = false,
|
|
101
|
-
className
|
|
101
|
+
className,
|
|
102
102
|
icon,
|
|
103
103
|
dir = "ltr",
|
|
104
|
-
generateOnTitleChange = false,
|
|
105
104
|
transliteratePersian = true
|
|
106
105
|
}) {
|
|
107
|
-
const
|
|
108
|
-
|
|
106
|
+
const handleGenerate = () => {
|
|
107
|
+
if (!title.trim() || disabled) return;
|
|
108
|
+
onChange(createSlug(title, transliteratePersian));
|
|
109
109
|
};
|
|
110
110
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_clsx.default)("w-full space-y-1.5", className), children: [
|
|
111
|
-
label && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
label
|
|
115
|
-
] }),
|
|
116
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
117
|
-
"button",
|
|
118
|
-
{
|
|
119
|
-
type: "button",
|
|
120
|
-
onClick: createSlug,
|
|
121
|
-
disabled: disabled || !title.trim(),
|
|
122
|
-
className: (0, import_clsx.default)(
|
|
123
|
-
"inline-flex items-center gap-1.5 rounded-lg px-3 py-2 text-xs font-medium",
|
|
124
|
-
"text-white transition-all duration-200",
|
|
125
|
-
"bg-[var(--color-primary)]",
|
|
126
|
-
"hover:bg-[var(--color-primary-soft)]",
|
|
127
|
-
"focus:outline-none focus:ring-4 focus:ring-[color-mix(in_oklab,var(--color-primary)_15%,transparent)]",
|
|
128
|
-
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
129
|
-
),
|
|
130
|
-
children: [
|
|
131
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.WandSparkles, { className: "size-4" }),
|
|
132
|
-
buttonText
|
|
133
|
-
]
|
|
134
|
-
}
|
|
135
|
-
)
|
|
111
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "flex items-center gap-2 text-sm font-medium text-(--color-text-primary)", children: [
|
|
112
|
+
icon,
|
|
113
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: label })
|
|
136
114
|
] }),
|
|
137
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative
|
|
138
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pointer-events-none absolute -inset-[1px] rounded-lg opacity-0 transition group-focus-within:opacity-100" }),
|
|
115
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative", children: [
|
|
139
116
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
140
117
|
"input",
|
|
141
118
|
{
|
|
@@ -147,13 +124,16 @@ function SlugGenerator({
|
|
|
147
124
|
onKeyDown: (event) => {
|
|
148
125
|
if (event.key === "Enter") {
|
|
149
126
|
event.preventDefault();
|
|
150
|
-
|
|
127
|
+
handleGenerate();
|
|
151
128
|
}
|
|
152
129
|
},
|
|
153
130
|
className: (0, import_clsx.default)(
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
"
|
|
131
|
+
"w-full rounded-lg border border-(--color-border)",
|
|
132
|
+
"bg-(--color-bg-main)",
|
|
133
|
+
"py-3 pe-4 ps-32",
|
|
134
|
+
"text-sm text-(--color-text-primary)",
|
|
135
|
+
"outline-none transition-all",
|
|
136
|
+
"placeholder:text-(--color-text-secondary)/70",
|
|
157
137
|
"hover:border-[color-mix(in_oklab,var(--color-primary)_22%,var(--color-border))]",
|
|
158
138
|
"focus:border-[color-mix(in_oklab,var(--color-primary)_45%,var(--color-border))]",
|
|
159
139
|
"focus:ring-4 focus:ring-[color-mix(in_oklab,var(--color-primary)_12%,transparent)]",
|
|
@@ -162,41 +142,27 @@ function SlugGenerator({
|
|
|
162
142
|
)
|
|
163
143
|
}
|
|
164
144
|
),
|
|
165
|
-
|
|
166
|
-
"button",
|
|
167
|
-
{
|
|
168
|
-
type: "button",
|
|
169
|
-
onClick: createSlug,
|
|
170
|
-
disabled: disabled || !title.trim(),
|
|
171
|
-
className: (0, import_clsx.default)(
|
|
172
|
-
"absolute inset-y-1.5 end-1.5 inline-flex items-center gap-1.5",
|
|
173
|
-
"rounded-md px-3 text-xs font-medium text-white",
|
|
174
|
-
"bg-[var(--color-primary)] transition-all duration-200",
|
|
175
|
-
"hover:bg-[var(--color-primary-soft)]",
|
|
176
|
-
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
177
|
-
),
|
|
178
|
-
children: [
|
|
179
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.WandSparkles, { className: "size-4" }),
|
|
180
|
-
buttonText
|
|
181
|
-
]
|
|
182
|
-
}
|
|
183
|
-
),
|
|
184
|
-
label && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
145
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
185
146
|
"button",
|
|
186
147
|
{
|
|
187
148
|
type: "button",
|
|
188
|
-
onClick:
|
|
149
|
+
onClick: handleGenerate,
|
|
189
150
|
disabled: disabled || !title.trim(),
|
|
190
151
|
className: (0, import_clsx.default)(
|
|
191
|
-
"absolute inset-y-1.5
|
|
192
|
-
"
|
|
193
|
-
"
|
|
194
|
-
"
|
|
152
|
+
"absolute inset-y-1.5 start-1.5",
|
|
153
|
+
"inline-flex items-center justify-center gap-1.5",
|
|
154
|
+
"rounded-md px-3",
|
|
155
|
+
"text-xs font-medium text-white",
|
|
156
|
+
"bg-(--color-primary)",
|
|
157
|
+
"transition-all duration-200",
|
|
158
|
+
"hover:bg-(--color-primary-soft)",
|
|
159
|
+
"focus:outline-none",
|
|
160
|
+
"focus:ring-2 focus:ring-(--color-primary)/30",
|
|
195
161
|
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
196
162
|
),
|
|
197
163
|
children: [
|
|
198
164
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.WandSparkles, { className: "size-4" }),
|
|
199
|
-
buttonText
|
|
165
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: buttonText })
|
|
200
166
|
]
|
|
201
167
|
}
|
|
202
168
|
)
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/SlugGenerator.tsx"],"sourcesContent":["export { default as SlugGenerator } from \"./SlugGenerator\";\r\nexport type { SlugGeneratorProps } from \"./types\";","\"use client\";\r\n\r\nimport { WandSparkles } from \"lucide-react\";\r\nimport clsx from \"clsx\";\r\nimport type { SlugGeneratorProps } from \"./types\";\r\n\r\nconst PERSIAN_MAP: Record<string, string> = {\r\n ا: \"a\",\r\n آ: \"a\",\r\n ب: \"b\",\r\n پ: \"p\",\r\n ت: \"t\",\r\n ث: \"s\",\r\n ج: \"j\",\r\n چ: \"ch\",\r\n ح: \"h\",\r\n خ: \"kh\",\r\n د: \"d\",\r\n ذ: \"z\",\r\n ر: \"r\",\r\n ز: \"z\",\r\n ژ: \"zh\",\r\n س: \"s\",\r\n ش: \"sh\",\r\n ص: \"s\",\r\n ض: \"z\",\r\n ط: \"t\",\r\n ظ: \"z\",\r\n ع: \"a\",\r\n غ: \"gh\",\r\n ف: \"f\",\r\n ق: \"gh\",\r\n ک: \"k\",\r\n گ: \"g\",\r\n ل: \"l\",\r\n م: \"m\",\r\n ن: \"n\",\r\n و: \"v\",\r\n ه: \"h\",\r\n ی: \"y\",\r\n ئ: \"y\",\r\n ء: \"a\",\r\n ۀ: \"h\",\r\n ة: \"h\",\r\n ي: \"y\",\r\n ك: \"k\",\r\n};\r\n\r\nconst ARABIC_DIACRITICS = /[\\u064B-\\u065F\\u0670]/g;\r\n\r\nfunction transliterate(text: string) {\r\n return text\r\n .normalize(\"NFKC\")\r\n .replace(ARABIC_DIACRITICS, \"\")\r\n .split(\"\")\r\n .map((char) => PERSIAN_MAP[char] ?? char)\r\n .join(\"\");\r\n}\r\n\r\
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/SlugGenerator.tsx"],"sourcesContent":["export { default as SlugGenerator } from \"./SlugGenerator\";\r\nexport type { SlugGeneratorProps } from \"./types\";","\"use client\";\r\n\r\nimport { WandSparkles } from \"lucide-react\";\r\nimport clsx from \"clsx\";\r\nimport type { SlugGeneratorProps } from \"./types\";\r\n\r\nconst PERSIAN_MAP: Record<string, string> = {\r\n ا: \"a\",\r\n آ: \"a\",\r\n ب: \"b\",\r\n پ: \"p\",\r\n ت: \"t\",\r\n ث: \"s\",\r\n ج: \"j\",\r\n چ: \"ch\",\r\n ح: \"h\",\r\n خ: \"kh\",\r\n د: \"d\",\r\n ذ: \"z\",\r\n ر: \"r\",\r\n ز: \"z\",\r\n ژ: \"zh\",\r\n س: \"s\",\r\n ش: \"sh\",\r\n ص: \"s\",\r\n ض: \"z\",\r\n ط: \"t\",\r\n ظ: \"z\",\r\n ع: \"a\",\r\n غ: \"gh\",\r\n ف: \"f\",\r\n ق: \"gh\",\r\n ک: \"k\",\r\n گ: \"g\",\r\n ل: \"l\",\r\n م: \"m\",\r\n ن: \"n\",\r\n و: \"v\",\r\n ه: \"h\",\r\n ی: \"y\",\r\n ئ: \"y\",\r\n ء: \"a\",\r\n ۀ: \"h\",\r\n ة: \"h\",\r\n ي: \"y\",\r\n ك: \"k\",\r\n};\r\n\r\nconst ARABIC_DIACRITICS = /[\\u064B-\\u065F\\u0670]/g;\r\n\r\nfunction transliterate(text: string): string {\r\n return text\r\n .normalize(\"NFKC\")\r\n .replace(ARABIC_DIACRITICS, \"\")\r\n .split(\"\")\r\n .map((char) => PERSIAN_MAP[char] ?? char)\r\n .join(\"\");\r\n}\r\n\r\nexport function createSlug(\r\n title: string,\r\n transliteratePersian = true,\r\n): string {\r\n let source = title\r\n .normalize(\"NFKC\")\r\n .replace(ARABIC_DIACRITICS, \"\");\r\n\r\n if (transliteratePersian) {\r\n source = transliterate(source);\r\n }\r\n\r\n return source\r\n .toLowerCase()\r\n .trim()\r\n .replace(/['’`\"]/g, \"\")\r\n .replace(/[^a-z0-9\\s-]/g, \"\")\r\n .replace(/\\s+/g, \"-\")\r\n .replace(/-+/g, \"-\")\r\n .replace(/^-+|-+$/g, \"\");\r\n}\r\n\r\nexport default function SlugGenerator({\r\n title,\r\n value,\r\n onChange,\r\n label = \"Slug\",\r\n placeholder = \"your-slug\",\r\n buttonText = \"Generate\",\r\n disabled = false,\r\n className,\r\n icon,\r\n dir = \"ltr\",\r\n transliteratePersian = true,\r\n}: SlugGeneratorProps) {\r\n const handleGenerate = () => {\r\n if (!title.trim() || disabled) return;\r\n\r\n onChange(createSlug(title, transliteratePersian));\r\n };\r\n\r\n return (\r\n <div className={clsx(\"w-full space-y-1.5\", className)}>\r\n {label && (\r\n <label className=\"flex items-center gap-2 text-sm font-medium text-(--color-text-primary)\">\r\n {icon}\r\n <span>{label}</span>\r\n </label>\r\n )}\r\n\r\n <div className=\"relative\">\r\n <input\r\n dir={dir}\r\n value={value}\r\n onChange={(event) => onChange(event.target.value)}\r\n placeholder={placeholder}\r\n disabled={disabled}\r\n onKeyDown={(event) => {\r\n if (event.key === \"Enter\") {\r\n event.preventDefault();\r\n handleGenerate();\r\n }\r\n }}\r\n className={clsx(\r\n \"w-full rounded-lg border border-(--color-border)\",\r\n \"bg-(--color-bg-main)\",\r\n \"py-3 pe-4 ps-32\",\r\n \"text-sm text-(--color-text-primary)\",\r\n \"outline-none transition-all\",\r\n \"placeholder:text-(--color-text-secondary)/70\",\r\n \"hover:border-[color-mix(in_oklab,var(--color-primary)_22%,var(--color-border))]\",\r\n \"focus:border-[color-mix(in_oklab,var(--color-primary)_45%,var(--color-border))]\",\r\n \"focus:ring-4 focus:ring-[color-mix(in_oklab,var(--color-primary)_12%,transparent)]\",\r\n \"dark:bg-white/[0.03]\",\r\n \"disabled:cursor-not-allowed disabled:opacity-50\",\r\n )}\r\n />\r\n\r\n <button\r\n type=\"button\"\r\n onClick={handleGenerate}\r\n disabled={disabled || !title.trim()}\r\n className={clsx(\r\n \"absolute inset-y-1.5 start-1.5\",\r\n \"inline-flex items-center justify-center gap-1.5\",\r\n \"rounded-md px-3\",\r\n \"text-xs font-medium text-white\",\r\n \"bg-(--color-primary)\",\r\n \"transition-all duration-200\",\r\n \"hover:bg-(--color-primary-soft)\",\r\n \"focus:outline-none\",\r\n \"focus:ring-2 focus:ring-(--color-primary)/30\",\r\n \"disabled:cursor-not-allowed disabled:opacity-50\",\r\n )}\r\n >\r\n <WandSparkles className=\"size-4\" />\r\n <span>{buttonText}</span>\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n}"],"mappings":"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","names":["clsx"]}
|
package/dist/index.mjs
CHANGED
|
@@ -47,12 +47,12 @@ var ARABIC_DIACRITICS = /[\u064B-\u065F\u0670]/g;
|
|
|
47
47
|
function transliterate(text) {
|
|
48
48
|
return text.normalize("NFKC").replace(ARABIC_DIACRITICS, "").split("").map((char) => PERSIAN_MAP[char] ?? char).join("");
|
|
49
49
|
}
|
|
50
|
-
function
|
|
50
|
+
function createSlug(title, transliteratePersian = true) {
|
|
51
51
|
let source = title.normalize("NFKC").replace(ARABIC_DIACRITICS, "");
|
|
52
52
|
if (transliteratePersian) {
|
|
53
53
|
source = transliterate(source);
|
|
54
54
|
}
|
|
55
|
-
return source.toLowerCase().trim().replace(/['’`"]/g, "").replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(
|
|
55
|
+
return source.toLowerCase().trim().replace(/['’`"]/g, "").replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
56
56
|
}
|
|
57
57
|
function SlugGenerator({
|
|
58
58
|
title,
|
|
@@ -62,44 +62,21 @@ function SlugGenerator({
|
|
|
62
62
|
placeholder = "your-slug",
|
|
63
63
|
buttonText = "Generate",
|
|
64
64
|
disabled = false,
|
|
65
|
-
className
|
|
65
|
+
className,
|
|
66
66
|
icon,
|
|
67
67
|
dir = "ltr",
|
|
68
|
-
generateOnTitleChange = false,
|
|
69
68
|
transliteratePersian = true
|
|
70
69
|
}) {
|
|
71
|
-
const
|
|
72
|
-
|
|
70
|
+
const handleGenerate = () => {
|
|
71
|
+
if (!title.trim() || disabled) return;
|
|
72
|
+
onChange(createSlug(title, transliteratePersian));
|
|
73
73
|
};
|
|
74
74
|
return /* @__PURE__ */ jsxs("div", { className: clsx("w-full space-y-1.5", className), children: [
|
|
75
|
-
label && /* @__PURE__ */ jsxs("
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
label
|
|
79
|
-
] }),
|
|
80
|
-
/* @__PURE__ */ jsxs(
|
|
81
|
-
"button",
|
|
82
|
-
{
|
|
83
|
-
type: "button",
|
|
84
|
-
onClick: createSlug,
|
|
85
|
-
disabled: disabled || !title.trim(),
|
|
86
|
-
className: clsx(
|
|
87
|
-
"inline-flex items-center gap-1.5 rounded-lg px-3 py-2 text-xs font-medium",
|
|
88
|
-
"text-white transition-all duration-200",
|
|
89
|
-
"bg-[var(--color-primary)]",
|
|
90
|
-
"hover:bg-[var(--color-primary-soft)]",
|
|
91
|
-
"focus:outline-none focus:ring-4 focus:ring-[color-mix(in_oklab,var(--color-primary)_15%,transparent)]",
|
|
92
|
-
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
93
|
-
),
|
|
94
|
-
children: [
|
|
95
|
-
/* @__PURE__ */ jsx(WandSparkles, { className: "size-4" }),
|
|
96
|
-
buttonText
|
|
97
|
-
]
|
|
98
|
-
}
|
|
99
|
-
)
|
|
75
|
+
label && /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm font-medium text-(--color-text-primary)", children: [
|
|
76
|
+
icon,
|
|
77
|
+
/* @__PURE__ */ jsx("span", { children: label })
|
|
100
78
|
] }),
|
|
101
|
-
/* @__PURE__ */ jsxs("div", { className: "relative
|
|
102
|
-
/* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute -inset-[1px] rounded-lg opacity-0 transition group-focus-within:opacity-100" }),
|
|
79
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
103
80
|
/* @__PURE__ */ jsx(
|
|
104
81
|
"input",
|
|
105
82
|
{
|
|
@@ -111,13 +88,16 @@ function SlugGenerator({
|
|
|
111
88
|
onKeyDown: (event) => {
|
|
112
89
|
if (event.key === "Enter") {
|
|
113
90
|
event.preventDefault();
|
|
114
|
-
|
|
91
|
+
handleGenerate();
|
|
115
92
|
}
|
|
116
93
|
},
|
|
117
94
|
className: clsx(
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
"
|
|
95
|
+
"w-full rounded-lg border border-(--color-border)",
|
|
96
|
+
"bg-(--color-bg-main)",
|
|
97
|
+
"py-3 pe-4 ps-32",
|
|
98
|
+
"text-sm text-(--color-text-primary)",
|
|
99
|
+
"outline-none transition-all",
|
|
100
|
+
"placeholder:text-(--color-text-secondary)/70",
|
|
121
101
|
"hover:border-[color-mix(in_oklab,var(--color-primary)_22%,var(--color-border))]",
|
|
122
102
|
"focus:border-[color-mix(in_oklab,var(--color-primary)_45%,var(--color-border))]",
|
|
123
103
|
"focus:ring-4 focus:ring-[color-mix(in_oklab,var(--color-primary)_12%,transparent)]",
|
|
@@ -126,41 +106,27 @@ function SlugGenerator({
|
|
|
126
106
|
)
|
|
127
107
|
}
|
|
128
108
|
),
|
|
129
|
-
|
|
130
|
-
"button",
|
|
131
|
-
{
|
|
132
|
-
type: "button",
|
|
133
|
-
onClick: createSlug,
|
|
134
|
-
disabled: disabled || !title.trim(),
|
|
135
|
-
className: clsx(
|
|
136
|
-
"absolute inset-y-1.5 end-1.5 inline-flex items-center gap-1.5",
|
|
137
|
-
"rounded-md px-3 text-xs font-medium text-white",
|
|
138
|
-
"bg-[var(--color-primary)] transition-all duration-200",
|
|
139
|
-
"hover:bg-[var(--color-primary-soft)]",
|
|
140
|
-
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
141
|
-
),
|
|
142
|
-
children: [
|
|
143
|
-
/* @__PURE__ */ jsx(WandSparkles, { className: "size-4" }),
|
|
144
|
-
buttonText
|
|
145
|
-
]
|
|
146
|
-
}
|
|
147
|
-
),
|
|
148
|
-
label && /* @__PURE__ */ jsxs(
|
|
109
|
+
/* @__PURE__ */ jsxs(
|
|
149
110
|
"button",
|
|
150
111
|
{
|
|
151
112
|
type: "button",
|
|
152
|
-
onClick:
|
|
113
|
+
onClick: handleGenerate,
|
|
153
114
|
disabled: disabled || !title.trim(),
|
|
154
115
|
className: clsx(
|
|
155
|
-
"absolute inset-y-1.5
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
116
|
+
"absolute inset-y-1.5 start-1.5",
|
|
117
|
+
"inline-flex items-center justify-center gap-1.5",
|
|
118
|
+
"rounded-md px-3",
|
|
119
|
+
"text-xs font-medium text-white",
|
|
120
|
+
"bg-(--color-primary)",
|
|
121
|
+
"transition-all duration-200",
|
|
122
|
+
"hover:bg-(--color-primary-soft)",
|
|
123
|
+
"focus:outline-none",
|
|
124
|
+
"focus:ring-2 focus:ring-(--color-primary)/30",
|
|
159
125
|
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
160
126
|
),
|
|
161
127
|
children: [
|
|
162
128
|
/* @__PURE__ */ jsx(WandSparkles, { className: "size-4" }),
|
|
163
|
-
buttonText
|
|
129
|
+
/* @__PURE__ */ jsx("span", { children: buttonText })
|
|
164
130
|
]
|
|
165
131
|
}
|
|
166
132
|
)
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/SlugGenerator.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport { WandSparkles } from \"lucide-react\";\r\nimport clsx from \"clsx\";\r\nimport type { SlugGeneratorProps } from \"./types\";\r\n\r\nconst PERSIAN_MAP: Record<string, string> = {\r\n ا: \"a\",\r\n آ: \"a\",\r\n ب: \"b\",\r\n پ: \"p\",\r\n ت: \"t\",\r\n ث: \"s\",\r\n ج: \"j\",\r\n چ: \"ch\",\r\n ح: \"h\",\r\n خ: \"kh\",\r\n د: \"d\",\r\n ذ: \"z\",\r\n ر: \"r\",\r\n ز: \"z\",\r\n ژ: \"zh\",\r\n س: \"s\",\r\n ش: \"sh\",\r\n ص: \"s\",\r\n ض: \"z\",\r\n ط: \"t\",\r\n ظ: \"z\",\r\n ع: \"a\",\r\n غ: \"gh\",\r\n ف: \"f\",\r\n ق: \"gh\",\r\n ک: \"k\",\r\n گ: \"g\",\r\n ل: \"l\",\r\n م: \"m\",\r\n ن: \"n\",\r\n و: \"v\",\r\n ه: \"h\",\r\n ی: \"y\",\r\n ئ: \"y\",\r\n ء: \"a\",\r\n ۀ: \"h\",\r\n ة: \"h\",\r\n ي: \"y\",\r\n ك: \"k\",\r\n};\r\n\r\nconst ARABIC_DIACRITICS = /[\\u064B-\\u065F\\u0670]/g;\r\n\r\nfunction transliterate(text: string) {\r\n return text\r\n .normalize(\"NFKC\")\r\n .replace(ARABIC_DIACRITICS, \"\")\r\n .split(\"\")\r\n .map((char) => PERSIAN_MAP[char] ?? char)\r\n .join(\"\");\r\n}\r\n\r\
|
|
1
|
+
{"version":3,"sources":["../src/SlugGenerator.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport { WandSparkles } from \"lucide-react\";\r\nimport clsx from \"clsx\";\r\nimport type { SlugGeneratorProps } from \"./types\";\r\n\r\nconst PERSIAN_MAP: Record<string, string> = {\r\n ا: \"a\",\r\n آ: \"a\",\r\n ب: \"b\",\r\n پ: \"p\",\r\n ت: \"t\",\r\n ث: \"s\",\r\n ج: \"j\",\r\n چ: \"ch\",\r\n ح: \"h\",\r\n خ: \"kh\",\r\n د: \"d\",\r\n ذ: \"z\",\r\n ر: \"r\",\r\n ز: \"z\",\r\n ژ: \"zh\",\r\n س: \"s\",\r\n ش: \"sh\",\r\n ص: \"s\",\r\n ض: \"z\",\r\n ط: \"t\",\r\n ظ: \"z\",\r\n ع: \"a\",\r\n غ: \"gh\",\r\n ف: \"f\",\r\n ق: \"gh\",\r\n ک: \"k\",\r\n گ: \"g\",\r\n ل: \"l\",\r\n م: \"m\",\r\n ن: \"n\",\r\n و: \"v\",\r\n ه: \"h\",\r\n ی: \"y\",\r\n ئ: \"y\",\r\n ء: \"a\",\r\n ۀ: \"h\",\r\n ة: \"h\",\r\n ي: \"y\",\r\n ك: \"k\",\r\n};\r\n\r\nconst ARABIC_DIACRITICS = /[\\u064B-\\u065F\\u0670]/g;\r\n\r\nfunction transliterate(text: string): string {\r\n return text\r\n .normalize(\"NFKC\")\r\n .replace(ARABIC_DIACRITICS, \"\")\r\n .split(\"\")\r\n .map((char) => PERSIAN_MAP[char] ?? char)\r\n .join(\"\");\r\n}\r\n\r\nexport function createSlug(\r\n title: string,\r\n transliteratePersian = true,\r\n): string {\r\n let source = title\r\n .normalize(\"NFKC\")\r\n .replace(ARABIC_DIACRITICS, \"\");\r\n\r\n if (transliteratePersian) {\r\n source = transliterate(source);\r\n }\r\n\r\n return source\r\n .toLowerCase()\r\n .trim()\r\n .replace(/['’`\"]/g, \"\")\r\n .replace(/[^a-z0-9\\s-]/g, \"\")\r\n .replace(/\\s+/g, \"-\")\r\n .replace(/-+/g, \"-\")\r\n .replace(/^-+|-+$/g, \"\");\r\n}\r\n\r\nexport default function SlugGenerator({\r\n title,\r\n value,\r\n onChange,\r\n label = \"Slug\",\r\n placeholder = \"your-slug\",\r\n buttonText = \"Generate\",\r\n disabled = false,\r\n className,\r\n icon,\r\n dir = \"ltr\",\r\n transliteratePersian = true,\r\n}: SlugGeneratorProps) {\r\n const handleGenerate = () => {\r\n if (!title.trim() || disabled) return;\r\n\r\n onChange(createSlug(title, transliteratePersian));\r\n };\r\n\r\n return (\r\n <div className={clsx(\"w-full space-y-1.5\", className)}>\r\n {label && (\r\n <label className=\"flex items-center gap-2 text-sm font-medium text-(--color-text-primary)\">\r\n {icon}\r\n <span>{label}</span>\r\n </label>\r\n )}\r\n\r\n <div className=\"relative\">\r\n <input\r\n dir={dir}\r\n value={value}\r\n onChange={(event) => onChange(event.target.value)}\r\n placeholder={placeholder}\r\n disabled={disabled}\r\n onKeyDown={(event) => {\r\n if (event.key === \"Enter\") {\r\n event.preventDefault();\r\n handleGenerate();\r\n }\r\n }}\r\n className={clsx(\r\n \"w-full rounded-lg border border-(--color-border)\",\r\n \"bg-(--color-bg-main)\",\r\n \"py-3 pe-4 ps-32\",\r\n \"text-sm text-(--color-text-primary)\",\r\n \"outline-none transition-all\",\r\n \"placeholder:text-(--color-text-secondary)/70\",\r\n \"hover:border-[color-mix(in_oklab,var(--color-primary)_22%,var(--color-border))]\",\r\n \"focus:border-[color-mix(in_oklab,var(--color-primary)_45%,var(--color-border))]\",\r\n \"focus:ring-4 focus:ring-[color-mix(in_oklab,var(--color-primary)_12%,transparent)]\",\r\n \"dark:bg-white/[0.03]\",\r\n \"disabled:cursor-not-allowed disabled:opacity-50\",\r\n )}\r\n />\r\n\r\n <button\r\n type=\"button\"\r\n onClick={handleGenerate}\r\n disabled={disabled || !title.trim()}\r\n className={clsx(\r\n \"absolute inset-y-1.5 start-1.5\",\r\n \"inline-flex items-center justify-center gap-1.5\",\r\n \"rounded-md px-3\",\r\n \"text-xs font-medium text-white\",\r\n \"bg-(--color-primary)\",\r\n \"transition-all duration-200\",\r\n \"hover:bg-(--color-primary-soft)\",\r\n \"focus:outline-none\",\r\n \"focus:ring-2 focus:ring-(--color-primary)/30\",\r\n \"disabled:cursor-not-allowed disabled:opacity-50\",\r\n )}\r\n >\r\n <WandSparkles className=\"size-4\" />\r\n <span>{buttonText}</span>\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n}"],"mappings":"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","names":[]}
|