margo-ui 2.1.0 → 3.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "margo-ui",
3
- "version": "2.1.0",
3
+ "version": "3.0.1",
4
4
  "description": "React UI kit built on Tailwind CSS v4 design tokens, themeable through plain CSS custom properties.",
5
5
  "keywords": [
6
6
  "react",
@@ -1,6 +1,6 @@
1
1
  export const inputBaseClassName = `group/input flex w-full cursor-text items-center gap-1 rounded-lg border-2 px-3 py-2 text-on-main
2
2
  text-sm select-none min-h-[2.5rem] bg-low
3
- border-transparent text-medium hover:border-on-main hover:text-on-main hover:shadow-input
3
+ border-transparent text-medium hover:border-on-main hover:text-on-main hover:shadow-item
4
4
  focus-within:border-primary focus-within:text-on-main
5
5
  has-[input:disabled]:pointer-events-none has-[input:disabled]:cursor-auto has-[input:disabled]:opacity-40`;
6
6
 
@@ -1,6 +1,6 @@
1
1
  export const selectBaseClassName = `group/select relative flex min-h-[2.5rem] w-full items-center gap-1 rounded-lg
2
2
  border-2 border-transparent bg-low text-sm text-medium select-none
3
- hover:border-on-main hover:text-on-main hover:shadow-input
3
+ hover:border-on-main hover:text-on-main hover:shadow-item
4
4
  focus-within:border-primary focus-within:text-on-main
5
5
  has-[select:disabled]:pointer-events-none has-[select:disabled]:opacity-40`;
6
6
 
@@ -2,7 +2,7 @@ export const tableWrapperClassName = "w-full overflow-x-auto overscroll-x-none r
2
2
 
3
3
  export const tableBaseClassName = "w-full border-collapse text-xs text-on-main";
4
4
 
5
- export const tableHeadClassName = "border-b-2 border-border bg-neutral/40 text-left";
5
+ export const tableHeadClassName = "border-b-2 border-border bg-low text-left";
6
6
 
7
7
  export const tableBodyClassName = "align-top";
8
8
 
package/src/css/theme.css CHANGED
@@ -29,7 +29,6 @@
29
29
  --shadow-card: var(--margo-shadow-card);
30
30
  --shadow-button: var(--margo-shadow-button);
31
31
  --shadow-item: var(--margo-shadow-item);
32
- --shadow-input: var(--margo-shadow-input);
33
32
  --shadow-chip: var(--margo-shadow-chip);
34
33
 
35
34
  /* Durations */
@@ -52,33 +52,19 @@
52
52
 
53
53
  --margo-color-neutral: #ffffff;
54
54
  --margo-color-on-neutral: #000000;
55
- --margo-color-main: #edecec;
55
+ --margo-color-main: #f3f3f3;
56
56
  --margo-color-on-main: #151515;
57
57
  --margo-color-primary: #57e550;
58
58
  --margo-color-primary-darken: #45b93f;
59
- --margo-color-low: color-mix(in srgb, var(--margo-color-on-main) 4%, var(--margo-color-main));
60
- --margo-color-low-alpha: color-mix(in srgb, var(--margo-color-on-main) 4%, transparent);
59
+ --margo-color-low: color-mix(in srgb, var(--margo-color-on-main) 3.5%, var(--margo-color-main));
60
+ --margo-color-low-alpha: color-mix(in srgb, var(--margo-color-on-main) 3.5%, transparent);
61
61
  --margo-color-medium: #808080;
62
62
  --margo-color-border: #cecece;
63
63
 
64
64
  --margo-shadow-card: 0 8px 6px -4px rgb(220, 220, 220, 0.5);
65
65
  --margo-shadow-button: 0 2px 3px -1px rgb(220, 220, 220, 0.6);
66
66
  --margo-shadow-item: 0 3px 3px -3px rgba(139, 139, 139, 0.6);
67
- --margo-shadow-input: 0 3px 3px -3px rgba(139, 139, 139, 0.6);
68
67
  --margo-shadow-chip: 0 1px 3px -1px rgb(0, 0, 0, 0.6);
69
-
70
- --margo-code-surface: #fbfbfb;
71
- --margo-code-bar: #f1f1f1;
72
- --margo-code-plain: #24292f;
73
- --margo-code-comment: #8b949e;
74
- --margo-code-string: #0a7d3f;
75
- --margo-code-keyword: #a5309a;
76
- --margo-code-number: #b3510f;
77
- --margo-code-tag: #1f6fd6;
78
- --margo-code-attr: #7a5cd6;
79
- --margo-code-fn: #0f7c93;
80
- --margo-code-type: #1f6fd6;
81
- --margo-code-punct: #6e7781;
82
68
  }
83
69
 
84
70
  .dark {
@@ -87,7 +73,7 @@
87
73
  --margo-color-neutral: #000000;
88
74
  --margo-color-on-neutral: #ffffff;
89
75
  --margo-color-main: #151515;
90
- --margo-color-on-main: #eeeeee;
76
+ --margo-color-on-main: #f3f3f3;
91
77
  --margo-color-primary: #57e550;
92
78
  --margo-color-primary-darken: #45b93f;
93
79
  --margo-color-low: color-mix(in srgb, var(--margo-color-on-main) 2.5%, var(--margo-color-main));
@@ -98,21 +84,7 @@
98
84
  --margo-shadow-card: 0 4px 12px -4px rgb(0, 0, 0, 0.5);
99
85
  --margo-shadow-button: 0 2px 6px -2px rgb(0, 0, 0, 0.5);
100
86
  --margo-shadow-item: 0 2px 3px -2px rgb(0, 0, 0, 0.5);
101
- --margo-shadow-input: 0 2px 3px -2px rgb(0, 0, 0, 0.5);
102
87
  --margo-shadow-chip: 0 1px 3px -1px rgb(0, 0, 0, 0.5);
103
-
104
- --margo-code-surface: #0d0d0d;
105
- --margo-code-bar: #161616;
106
- --margo-code-plain: #e6e6e6;
107
- --margo-code-comment: #6b6b6b;
108
- --margo-code-string: #7ee787;
109
- --margo-code-keyword: #ff7bd5;
110
- --margo-code-number: #ffab70;
111
- --margo-code-tag: #79c0ff;
112
- --margo-code-attr: #c3a6ff;
113
- --margo-code-fn: #56d4dd;
114
- --margo-code-type: #79c0ff;
115
- --margo-code-punct: #8b949e;
116
88
  }
117
89
 
118
90
  @media (prefers-reduced-motion: reduce) {
package/src/index.ts CHANGED
@@ -19,7 +19,6 @@ export { Toggle } from "./components/toggle/toggle.js";
19
19
  export { Splash } from "./components/splash/splash.js";
20
20
  export { Select } from "./components/select/select.js";
21
21
  export { Sheet } from "./components/sheet/sheet.js";
22
- export { Snippet } from "./components/snippet/snippet.js";
23
22
  export { Spinner } from "./components/spinner/spinner.js";
24
23
  export { Tooltip } from "./components/tooltip/tooltip.js";
25
24
 
@@ -77,7 +76,6 @@ export type {
77
76
  export type { SplashProps, SplashServeProps } from "./components/splash/type.js";
78
77
  export type { SelectOwnProps, SelectProps } from "./components/select/type.js";
79
78
  export type { SheetBodyProps, SheetFooterProps, SheetProps, SheetSide } from "./components/sheet/type.js";
80
- export type { SnippetPreviewProps, SnippetProps, SnippetToken, SnippetTokenType } from "./components/snippet/type.js";
81
79
  export type { SpinnerProps } from "./components/spinner/type.js";
82
80
  export type { ToggleProps } from "./components/toggle/type.js";
83
81
  export type { TooltipPosition, TooltipProps } from "./components/tooltip/type.js";
@@ -1,83 +0,0 @@
1
- import type { SnippetToken, SnippetTokenType } from "./type.js";
2
-
3
- const KEYWORDS = [
4
- "as",
5
- "async",
6
- "await",
7
- "break",
8
- "case",
9
- "catch",
10
- "class",
11
- "const",
12
- "continue",
13
- "default",
14
- "delete",
15
- "do",
16
- "else",
17
- "export",
18
- "extends",
19
- "false",
20
- "for",
21
- "from",
22
- "function",
23
- "if",
24
- "implements",
25
- "import",
26
- "in",
27
- "instanceof",
28
- "interface",
29
- "let",
30
- "new",
31
- "null",
32
- "of",
33
- "readonly",
34
- "return",
35
- "satisfies",
36
- "switch",
37
- "this",
38
- "throw",
39
- "true",
40
- "try",
41
- "type",
42
- "typeof",
43
- "undefined",
44
- "var",
45
- "void",
46
- "while",
47
- "yield",
48
- ];
49
-
50
- const PATTERNS: readonly { type: SnippetTokenType; source: string }[] = [
51
- { type: "comment", source: "\\/\\/[^\\n]*|\\/\\*[\\s\\S]*?\\*\\/" },
52
- { type: "string", source: "\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|`(?:[^`\\\\]|\\\\.)*`" },
53
- { type: "tag", source: "<\\/?[A-Za-z][\\w.$]*" },
54
- { type: "keyword", source: `\\b(?:${KEYWORDS.join("|")})\\b` },
55
- { type: "number", source: "\\b\\d+(?:\\.\\d+)?\\b" },
56
- { type: "attr", source: "\\b[A-Za-z_$][\\w$]*(?=\\s*[=:](?!=))" },
57
- { type: "fn", source: "\\b[A-Za-z_$][\\w$]*(?=\\s*\\()" },
58
- { type: "type", source: "\\b[A-Z][\\w$]*\\b" },
59
- { type: "punct", source: "[{}()\\[\\]<>=;,.:!?|&+\\-*/]" },
60
- ];
61
-
62
- const TOKENIZER = new RegExp(PATTERNS.map((pattern) => `(${pattern.source})`).join("|"), "g");
63
-
64
- export const snippetHighlight = (code: string): SnippetToken[] => {
65
- const tokens: SnippetToken[] = [];
66
- let cursor = 0;
67
- let match: RegExpExecArray | null;
68
-
69
- TOKENIZER.lastIndex = 0;
70
-
71
- while ((match = TOKENIZER.exec(code)) !== null) {
72
- if (match.index > cursor) tokens.push({ type: "plain", value: code.slice(cursor, match.index) });
73
-
74
- const groupIndex = PATTERNS.findIndex((_, index) => match![index + 1] !== undefined);
75
-
76
- tokens.push({ type: PATTERNS[groupIndex].type, value: match[0] });
77
- cursor = match.index + match[0].length;
78
- }
79
-
80
- if (cursor < code.length) tokens.push({ type: "plain", value: code.slice(cursor) });
81
-
82
- return tokens;
83
- };
@@ -1,80 +0,0 @@
1
- import { useState } from "react";
2
-
3
- import { MdCheck, MdContentCopy } from "react-icons/md";
4
-
5
- import { Guard, List, Swap, Tag } from "react-renderable";
6
-
7
- import { cn } from "../../utils/cn/cn.js";
8
- import { Button } from "../button/button.js";
9
- import { snippetHighlight } from "./highlight.js";
10
- import {
11
- snippetBarClassName,
12
- snippetBaseClassName,
13
- snippetCodeClassName,
14
- snippetCopyClassName,
15
- snippetPreviewClassName,
16
- snippetTitleClassName,
17
- snippetTokenClassName,
18
- } from "./style.js";
19
-
20
- import type { ElementType } from "react";
21
- import { MaskGradientX } from "../../hoc/mask_gradient_x/mask_gradient_x.js";
22
- import type { SnippetPreviewProps, SnippetProps } from "./type.js";
23
-
24
- export const Snippet = <T extends ElementType = "div">({
25
- snippet,
26
- title,
27
- className,
28
- children,
29
- ...rest
30
- }: SnippetProps<T>) => {
31
- const [isCopied, setIsCopied] = useState(false);
32
- const source = snippet.trim();
33
-
34
- const handleCopy = async () => {
35
- await navigator.clipboard.writeText(source);
36
- setIsCopied(true);
37
- window.setTimeout(() => setIsCopied(false), 1500);
38
- };
39
-
40
- return (
41
- <Tag {...Tag.forward<T>(rest)} className={cn(snippetBaseClassName, className)}>
42
- <div className={snippetBarClassName}>
43
- <Guard guardIf={!title} shouldHide>
44
- <span className={snippetTitleClassName}>{title}</span>
45
- </Guard>
46
- <Button onClickBlur={handleCopy} aria-label="copy" aria-pressed={isCopied} className={snippetCopyClassName}>
47
- <Button.Icon
48
- icon={
49
- <Swap.Boolean
50
- swapOn={isCopied}
51
- components={[<MdContentCopy className="text-sm" />, <MdCheck className="text-sm" />]}
52
- />
53
- }
54
- />
55
- </Button>
56
- </div>
57
- <MaskGradientX fade="1rem">
58
- <pre className={snippetCodeClassName}>
59
- <code>
60
- <List
61
- array={snippetHighlight(source)}
62
- itemExtractor={({ row, index }) => (
63
- <span key={index} className={snippetTokenClassName[row.type]}>
64
- {row.value}
65
- </span>
66
- )}
67
- />
68
- </code>
69
- </pre>
70
- </MaskGradientX>
71
- {children}
72
- </Tag>
73
- );
74
- };
75
-
76
- Snippet.Preview = <T extends ElementType = "div">({ className, children, ...rest }: SnippetPreviewProps<T>) => (
77
- <Tag {...Tag.forward<T>(rest)} className={cn(snippetPreviewClassName, className)}>
78
- {children}
79
- </Tag>
80
- );
@@ -1,28 +0,0 @@
1
- import type { SnippetTokenType } from "./type.js";
2
-
3
- export const snippetBaseClassName = "rounded-lg border-2 border-border bg-(--margo-code-surface)";
4
-
5
- export const snippetBarClassName = `flex items-center justify-between gap-4 border-b-2 border-border
6
- rounded-t-[calc(var(--radius-lg)-var(--margo-border-width-2))] bg-(--margo-code-bar) px-3 py-2`;
7
-
8
- export const snippetTitleClassName = "text-mc uppercase tracking-widest text-medium";
9
-
10
- export const snippetCopyClassName = "ml-auto bg-neutral/60";
11
-
12
- export const snippetPreviewClassName =
13
- "flex flex-wrap items-center justify-center gap-6 rounded-b-lg border-t-2 border-border p-8";
14
-
15
- export const snippetCodeClassName = "overflow-x-auto p-4 text-xs leading-relaxed";
16
-
17
- export const snippetTokenClassName: Record<SnippetTokenType, string> = {
18
- plain: "text-(--margo-code-plain)",
19
- comment: "text-(--margo-code-comment) italic",
20
- string: "text-(--margo-code-string)",
21
- keyword: "text-(--margo-code-keyword)",
22
- number: "text-(--margo-code-number)",
23
- tag: "text-(--margo-code-tag)",
24
- attr: "text-(--margo-code-attr)",
25
- fn: "text-(--margo-code-fn)",
26
- type: "text-(--margo-code-type)",
27
- punct: "text-(--margo-code-punct)",
28
- };
@@ -1,29 +0,0 @@
1
- import type { TagProps } from "react-renderable";
2
- import type { ElementType, ReactNode } from "react";
3
-
4
- export type SnippetTokenType =
5
- | "plain"
6
- | "comment"
7
- | "string"
8
- | "keyword"
9
- | "number"
10
- | "tag"
11
- | "attr"
12
- | "fn"
13
- | "type"
14
- | "punct";
15
-
16
- export type SnippetToken = {
17
- type: SnippetTokenType;
18
- value: string;
19
- };
20
-
21
- export type SnippetOwnProps = {
22
- snippet: string;
23
- title?: string;
24
- children?: ReactNode;
25
- };
26
-
27
- export type SnippetProps<T extends ElementType = "div"> = TagProps<T, SnippetOwnProps>;
28
-
29
- export type SnippetPreviewProps<T extends ElementType = "div"> = TagProps<T>;