@iyulab/enterprise 0.5.0 → 0.7.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/dist/FormRow.d.ts CHANGED
@@ -14,4 +14,4 @@ export declare function FormRow({ children, full, columns, className, style, }:
14
14
  columns?: number;
15
15
  className?: string;
16
16
  style?: CSSProperties;
17
- }): import("react").JSX.Element;
17
+ }): any;
@@ -2,6 +2,15 @@ import { CSSProperties, ReactNode } from 'react';
2
2
  /**
3
3
  * L2 폼 블록 — 제목이 붙은 필드 묶음.
4
4
  *
5
+ * 🔴**제목에 `text-transform: uppercase` 와 `letter-spacing` 을 걸지 않는다**(0.7.0 에서 제거).
6
+ * ⑴ 한글에는 대문자가 없어 `uppercase` 가 **아무 효과가 없고**, 제목에 영문이 섞이면
7
+ * 그것만 커져 오히려 어수선해진다.
8
+ * ⑵ 양수 `letter-spacing` 은 **한글 가독성을 떨어뜨린다** — 라틴 소문자 조판 관례를
9
+ * 그대로 옮기면 안 되는 자리다.
10
+ * ⇒ 위계는 **크기·굵기·색** 세 신호로만 만든다(타입 스케일의 `label` 단).
11
+ * 영문 전용 UI 에서 눈썹 텍스트 느낌이 필요하면 `titleStyle` 로 `--u-text-overline-*`
12
+ * 단을 직접 지정한다 — 그 단은 영문·숫자 라벨을 전제하고 양수 자간을 갖는다.
13
+ *
5
14
  * 오버라이드 계약(docs/lob-layers.md §2): 구조는 두고 **children 치환 + prop** 으로 바꾼다.
6
15
  * ⚠기본 스타일은 병합 가능한 형태로만 둔다 — 호출자의 `style` 이 뒤에 오므로 필요한
7
16
  * 항목만 골라 덮을 수 있다. 인라인으로 굳혀 두면 소비자 CSS 가 이길 수 없어(`!important`
@@ -14,4 +23,4 @@ export declare function FormSection({ title, children, className, style, titleSt
14
23
  style?: CSSProperties;
15
24
  /** 제목 줄만 따로 조정할 때. 블록을 통째로 갈아엎지 않기 위한 훅이다. */
16
25
  titleStyle?: CSSProperties;
17
- }): import("react").JSX.Element;
26
+ }): any;
package/dist/index.js CHANGED
@@ -1,9 +1,19 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { HttpClient } from "@iyulab/http-client";
3
+ import buildQuery from "odata-query";
3
4
  //#region src/FormSection.tsx
4
5
  /**
5
6
  * L2 폼 블록 — 제목이 붙은 필드 묶음.
6
7
  *
8
+ * 🔴**제목에 `text-transform: uppercase` 와 `letter-spacing` 을 걸지 않는다**(0.7.0 에서 제거).
9
+ * ⑴ 한글에는 대문자가 없어 `uppercase` 가 **아무 효과가 없고**, 제목에 영문이 섞이면
10
+ * 그것만 커져 오히려 어수선해진다.
11
+ * ⑵ 양수 `letter-spacing` 은 **한글 가독성을 떨어뜨린다** — 라틴 소문자 조판 관례를
12
+ * 그대로 옮기면 안 되는 자리다.
13
+ * ⇒ 위계는 **크기·굵기·색** 세 신호로만 만든다(타입 스케일의 `label` 단).
14
+ * 영문 전용 UI 에서 눈썹 텍스트 느낌이 필요하면 `titleStyle` 로 `--u-text-overline-*`
15
+ * 단을 직접 지정한다 — 그 단은 영문·숫자 라벨을 전제하고 양수 자간을 갖는다.
16
+ *
7
17
  * 오버라이드 계약(docs/lob-layers.md §2): 구조는 두고 **children 치환 + prop** 으로 바꾼다.
8
18
  * ⚠기본 스타일은 병합 가능한 형태로만 둔다 — 호출자의 `style` 이 뒤에 오므로 필요한
9
19
  * 항목만 골라 덮을 수 있다. 인라인으로 굳혀 두면 소비자 CSS 가 이길 수 없어(`!important`
@@ -13,19 +23,19 @@ function FormSection({ title, children, className, style, titleStyle }) {
13
23
  return /* @__PURE__ */ jsxs("div", {
14
24
  className,
15
25
  style: {
16
- marginBottom: "20px",
26
+ marginBottom: "var(--u-space-xl, 20px)",
17
27
  ...style
18
28
  },
19
29
  children: [/* @__PURE__ */ jsx("div", {
20
30
  style: {
21
- fontSize: "11px",
22
- fontWeight: 700,
23
- textTransform: "uppercase",
24
- letterSpacing: "0.5px",
31
+ fontSize: "var(--u-text-label-size, 13px)",
32
+ fontWeight: "var(--u-text-label-weight, 600)",
33
+ lineHeight: "var(--u-text-label-leading, 1.5)",
34
+ letterSpacing: "var(--u-text-label-tracking, 0)",
25
35
  color: "color-mix(in srgb, var(--u-primary-color, #1E88E5) 85%, black)",
26
- paddingBottom: "6px",
36
+ paddingBottom: "var(--u-space-xs, 6px)",
27
37
  borderBottom: "1px solid var(--u-border-color-weak, #EEEEEE)",
28
- marginBottom: "10px",
38
+ marginBottom: "var(--u-space-sm, 8px)",
29
39
  ...titleStyle
30
40
  },
31
41
  children: title
@@ -33,7 +43,7 @@ function FormSection({ title, children, className, style, titleStyle }) {
33
43
  style: {
34
44
  display: "flex",
35
45
  flexDirection: "column",
36
- gap: "8px"
46
+ gap: "var(--u-space-sm, 8px)"
37
47
  },
38
48
  children
39
49
  })]
@@ -62,7 +72,7 @@ function FormRow({ children, full, columns = 2, className, style }) {
62
72
  style: {
63
73
  display: "grid",
64
74
  gridTemplateColumns: `repeat(${columns}, 1fr)`,
65
- gap: "8px",
75
+ gap: "var(--u-space-sm, 8px)",
66
76
  ...style
67
77
  },
68
78
  children
@@ -540,270 +550,6 @@ var ApiConfig = class {
540
550
  }
541
551
  };
542
552
  //#endregion
543
- //#region node_modules/odata-query/dist/index.mjs
544
- var e = [
545
- "eq",
546
- "ne",
547
- "gt",
548
- "ge",
549
- "lt",
550
- "le"
551
- ];
552
- var t = [
553
- "and",
554
- "or",
555
- "not"
556
- ];
557
- var n = ["any", "all"];
558
- var r = [
559
- "startswith",
560
- "endswith",
561
- "contains",
562
- "matchespattern"
563
- ];
564
- var i = [
565
- "expand",
566
- "levels",
567
- "select",
568
- "skip",
569
- "top",
570
- "count",
571
- "orderby",
572
- "filter"
573
- ];
574
- var a = /\((.*)\)/;
575
- var o = /(?!indexof)\((\w+)\)/;
576
- function g(e, t) {
577
- if (t) {
578
- let n = e === "", r = o.test(e), i = a.test(e);
579
- return n ? t : r ? y(e, t, o) : i ? y(e, t, a) : `${t}/${e}`;
580
- }
581
- return e;
582
- }
583
- function _(e) {
584
- return t.indexOf(e) !== -1;
585
- }
586
- function v(e) {
587
- return `not (${e.join(" and ")})`;
588
- }
589
- function y(e, t, n) {
590
- return e.replace(n, (e, n) => n.trim() === "" ? `(${t})` : `(${t}/${n.trim()})`);
591
- }
592
- function b(e, t, n = []) {
593
- return `${e} eq ${w(t, n)}`;
594
- }
595
- function x({ key: e, value: t, aliases: n, propPrefix: r }) {
596
- let i = [], a = e, o = _(a), s = t.map((e) => O(e, n, r)).filter((e) => e).map((e) => o ? `(${e})` : e);
597
- return s.length && (o ? a === "not" ? i.push(v(s)) : i.push(`(${s.join(` ${a} `)})`) : i.push(s.join(` ${a} `))), i;
598
- }
599
- function S({ propName: e, value: t }) {
600
- let n = [], r = e, i = Object.keys(t).map((e) => k({ [e]: t[e] }));
601
- return i.length && (r === "not" ? n.push(v(i)) : n.push(`(${i.join(` ${r} `)})`)), n;
602
- }
603
- function C({ key: i, propName: a, value: o, aliases: s }) {
604
- let c = [];
605
- return "type" in o ? c.push(b(a, o, s)) : Object.keys(o).forEach((l) => {
606
- if (o[l] !== void 0) if (e.indexOf(l) !== -1) c.push(`${a} ${l} ${w(o[l], s)}`);
607
- else if (t.indexOf(l) !== -1) Array.isArray(o[l]) ? c.push(o[l].map((e) => "(" + O(e, s, a) + ")").join(` ${l} `)) : c.push("(" + O(o[l], s, a) + ")");
608
- else if (n.indexOf(l) !== -1) {
609
- let e = A({
610
- lambdaParameter: i.toLowerCase(),
611
- value: o[l],
612
- op: l,
613
- propName: a,
614
- aliases: s
615
- });
616
- e && c.push(e);
617
- } else if (l === "has") c.push(`${a} ${l} ${w(o[l], s)}`);
618
- else if (l === "in") {
619
- let e = Array.isArray(o[l]) ? o[l] : o[l].value.map((e) => ({
620
- type: o[l].type,
621
- value: e
622
- }));
623
- c.push(a + " in (" + e.map((e) => w(e, s)).join(",") + ")");
624
- } else if (r.indexOf(l) !== -1) c.push(`${l}(${a},${w(o[l], s)})`);
625
- else {
626
- let e = /\/not/g.test(a), t = e ? a.replace(/\/not/g, "") : a, n = e ? v([O({ [l]: o[l] }, s, t)]) : O({ [l]: o[l] }, s, t);
627
- n && c.push(n);
628
- }
629
- }), c;
630
- }
631
- function w(e, t) {
632
- if (typeof e == "string") return `'${D(e)}'`;
633
- if (e instanceof Date) return e.toISOString();
634
- if (typeof e == "number") return e;
635
- if (Array.isArray(e)) return `[${e.map((e) => w(e)).join(",")}]`;
636
- if (e === null) return e;
637
- if (typeof e == "object") switch (e.type) {
638
- case "raw":
639
- case "guid": return e.value;
640
- case "duration": return `duration'${e.value}'`;
641
- case "binary": return `binary'${e.value}'`;
642
- case "alias": return Array.isArray(t) && t.push(e), `@${e.name}`;
643
- case "json": return escape(JSON.stringify(e.value));
644
- case "decimal": return `${e.value}M`;
645
- default: return Object.entries(e).filter(([, e]) => e !== void 0).map(([e, n]) => `${e}=${w(n, t)}`).join(",");
646
- }
647
- return e;
648
- }
649
- function T(e, t, n, r) {
650
- return `${r}/${n}(${e}: ${e} ${n == "all" ? "ne" : "eq"} '${t}')`;
651
- }
652
- function E(e) {
653
- return e.replace(/'/g, "''");
654
- }
655
- function D(e) {
656
- return encodeURIComponent(E(e));
657
- }
658
- function O(e = {}, t = [], n = "") {
659
- return (Array.isArray(e) ? e : [e]).reduce((e, r) => {
660
- if (r) {
661
- let i = k(r, t, n);
662
- i && e.push(i);
663
- }
664
- return e;
665
- }, []).join(" and ");
666
- }
667
- function k(e = {}, t = [], n = "") {
668
- let r = "";
669
- return typeof e == "string" ? r = e : e && typeof e == "object" && (r = Object.keys(e).reduce((r, i) => {
670
- let a = e[i];
671
- if (a === void 0) return r;
672
- let o = i === "", s = g(i, n);
673
- if (o && Array.isArray(a)) return r.concat(a.map((e) => b(s, e)));
674
- let c = [
675
- "number",
676
- "string",
677
- "boolean"
678
- ].indexOf(typeof a) !== -1 || a instanceof Date || a === null, l = Array.isArray(a), u = typeof a == "object";
679
- if (c) r.push(b(s, a, t));
680
- else if (l) r.push(...x({
681
- key: i,
682
- value: a,
683
- aliases: t,
684
- propPrefix: n
685
- }));
686
- else if (_(s)) r.push(...S({
687
- propName: s,
688
- value: a
689
- }));
690
- else if (u) r.push(...C({
691
- key: i,
692
- propName: s,
693
- value: a,
694
- aliases: t
695
- }));
696
- else throw Error(`Unexpected value type: ${a}`);
697
- return r;
698
- }, []).join(" and ")), r;
699
- }
700
- function A({ lambdaParameter: e, value: t, op: n, propName: r, aliases: i }) {
701
- let a = "";
702
- if (typeof t == "string" || t instanceof String) a = T(e, t, n, r);
703
- else if (t) {
704
- let o = O(Array.isArray(t) ? t.reduce((e, t) => t.hasOwnProperty("") ? (e.hasOwnProperty("") || (e[""] = []), e[""].push(t[""]), e) : {
705
- ...e,
706
- ...t
707
- }, {}) : t, i, e);
708
- a = `${r}/${n}(${o ? `${e}:${o}` : ""})`;
709
- }
710
- return a;
711
- }
712
- function j(e) {
713
- if (typeof e == "number") return e;
714
- if (typeof e == "string") return e.indexOf("/") === -1 ? e : e.split("/").reverse().reduce((e, t, n, r) => n === 0 ? `$expand=${t}` : n === r.length - 1 ? `${t}(${e})` : `$expand=${t}(${e})`, "");
715
- if (Array.isArray(e)) return `${e.map((e) => j(e)).join(",")}`;
716
- if (typeof e == "object") {
717
- let t = Object.keys(e);
718
- return t.some((e) => i.indexOf(e.toLowerCase()) !== -1) ? t.map((t) => {
719
- let n;
720
- switch (t) {
721
- case "filter":
722
- n = O(e[t]);
723
- break;
724
- case "orderBy":
725
- n = F(e[t]);
726
- break;
727
- case "levels":
728
- case "count":
729
- case "skip":
730
- case "top":
731
- n = `${e[t]}`;
732
- break;
733
- default: n = j(e[t]);
734
- }
735
- return `$${t.toLowerCase()}=${n}`;
736
- }).join(";") : t.map((t) => {
737
- let n = j(e[t]);
738
- return n ? `${t}(${n})` : t;
739
- }).join(",");
740
- }
741
- return "";
742
- }
743
- function M(e) {
744
- return (Array.isArray(e) ? e : [e]).reduce((e, t) => {
745
- for (let n of Object.keys(t)) switch (n) {
746
- case "aggregate": {
747
- let r = t[n];
748
- r && e.push(`aggregate(${N(r)})`);
749
- break;
750
- }
751
- case "filter": {
752
- let r = t[n];
753
- if (r) {
754
- let t = O(r);
755
- t && e.push(`filter(${t})`);
756
- }
757
- break;
758
- }
759
- case "groupBy": {
760
- let r = t[n];
761
- r && e.push(`groupby(${P(r)})`);
762
- break;
763
- }
764
- default: throw Error(`Unsupported transform: ${n}`);
765
- }
766
- return e;
767
- }, []).join("/") || void 0;
768
- }
769
- function N(e) {
770
- return (Array.isArray(e) ? e : [e]).map((e) => typeof e == "string" ? e : Object.keys(e).map((t) => {
771
- let n = e[t];
772
- if (!n.with && n.as) return `${t} as ${n.as}`;
773
- if (!n.with) throw Error(`'with' property required for '${t}'`);
774
- if (!n.as) throw Error(`'as' property required for '${t}'`);
775
- return `${t} with ${n.with} as ${n.as}`;
776
- })).join(",");
777
- }
778
- function P(e) {
779
- if (!e.properties) throw Error("'properties' property required for groupBy");
780
- let t = `(${e.properties.join(",")})`;
781
- return e.transform && (t += `,${M(e.transform)}`), t;
782
- }
783
- function F(e, t = "") {
784
- return Array.isArray(e) ? e.map((e) => Array.isArray(e) && e.length === 2 && ["asc", "desc"].indexOf(e[1]) !== -1 ? e.join(" ") : e).map((e) => `${t}${String(e)}`).join(",") : typeof e == "object" ? Object.entries(e).map(([e, t]) => F(t, `${e}/`)).map((e) => `${t}${e}`).join(",") : `${t}${String(e)}`;
785
- }
786
- function I(e, t) {
787
- let n = Object.getOwnPropertyNames(t).filter((e) => t[e] !== void 0 && t[e] !== "").map((e) => `${e}=${t[e]}`);
788
- return n.length ? `${e}?${n.join("&")}` : e;
789
- }
790
- function L({ select: e, search: t, skiptoken: n, format: r, top: i, skip: a, filter: o, transform: s, orderBy: c, key: l, count: u, expand: d, action: f, func: p } = {}) {
791
- let m = "", h = [], g = {};
792
- if (l != null && (m += `(${w(l, h)})`), (o || typeof u == "object") && (g.$filter = O(typeof u == "object" ? u : o, h)), s && (g.$apply = M(s)), d && (g.$expand = j(d)), c && (g.$orderby = F(c)), u && (typeof u == "boolean" ? g.$count = !0 : m += "/$count"), typeof i == "number" && (g.$top = i), typeof a == "number" && (g.$skip = a), f && (m += `/${f}`), p) {
793
- if (typeof p == "string") m += `/${p}`;
794
- else if (typeof p == "object") {
795
- let [e] = Object.keys(p), t = w(p[e], h);
796
- m += `/${e}`, t !== "" && (m += `(${t})`);
797
- }
798
- }
799
- return h.length > 0 && Object.assign(g, h.reduce((e, t) => Object.assign(e, { [`@${t.name}`]: w(t.value) }), {})), t && (g.$search = encodeURIComponent(t)), I(m, {
800
- $select: e,
801
- $skiptoken: n,
802
- $format: r,
803
- ...g
804
- });
805
- }
806
- //#endregion
807
553
  //#region src/data/ODataService.ts
808
554
  /**
809
555
  * OData v4 + custom REST 서비스 팩토리.
@@ -929,7 +675,7 @@ function createODataService(config) {
929
675
  return res.json();
930
676
  }
931
677
  async function odataCount(entity, filter) {
932
- const qs = L({
678
+ const qs = buildQuery({
933
679
  filter,
934
680
  top: 0,
935
681
  count: true
@@ -0,0 +1,134 @@
1
+ /*
2
+ * @iyulab/enterprise — **하우스 스타일 프리셋** (이유랩 LOB 앱 기본값)
3
+ * ==========================================================================
4
+ *
5
+ * import '@iyulab/enterprise/styles/preset.css';
6
+ *
7
+ * ⚠**`@iyulab/components` 1.21.0 이상이 필요하다.** 이 파일은 값만 정하고, 그 값을 **읽는
8
+ * 쪽은 컴포넌트**다. 1.20.0 이하에는 타입 스케일·반경 상단 축이 아예 없어서 여기 적은
9
+ * `--u-text-*` 는 **아무도 읽지 않는다** — 에러 없이 절반만 적용된 것처럼 보인다.
10
+ * `peerDependencies` 에 선언해 두었으나 **optional** 이다(프리셋을 쓰지 않는 소비자는
11
+ * `components` 자체가 필요 없다). 즉 버전 불일치는 **경고 없이 조용하다** — 프리셋을
12
+ * 로드했는데 글자 크기가 안 바뀌면 먼저 이 버전을 본다.
13
+ *
14
+ * `@iyulab/components` 가 여는 **토큰 축**에 이유랩의 값을 채운 한 장이다.
15
+ * 축(이름·단 수)은 `components` 소유이고, 이 파일은 **값만** 정한다.
16
+ *
17
+ * ──────────────────────────────────────────────────────────────────────────
18
+ * ★★계약 — 이 세 줄이 이 파일의 전부다.
19
+ * ──────────────────────────────────────────────────────────────────────────
20
+ * ⑴ **선택적 로드다.** 로드하지 않은 소비자는 `components` 의 중립 기본값을 그대로 받는다.
21
+ * `@iyulab/enterprise` 는 공개 패키지이므로 외부 소비자도 이 값을 받게 되지만,
22
+ * **로드하지 않을 자유가 소비자에게 있다.**
23
+ * ⑵ **`--u-*` 값만 덮는다.** 새 클래스·새 선택자를 만들지 않는다. 만들기 시작하면
24
+ * 소비자가 그 선택자와 특이도 싸움을 하게 되고, 그때부터 이 파일은 프리셋이 아니라
25
+ * 또 하나의 프레임워크가 된다. (`tests/preset-contract.test.ts` 가 지킨다.)
26
+ * ⑶ 🔴**소비자가 항상 이긴다.** 아래 선택자는 `:where()` 로 감싸 **특이도 0** 이다 —
27
+ * 소비앱의 평범한 `:root { … }` 한 줄이 **로드 순서와 무관하게** 이 값을 덮는다.
28
+ * ★종전에 소비앱들이 `:root:not([theme="dark"])` 같은 **특이도 방어**를 쓰고 있었는데,
29
+ * 그것은 업스트림이 `:root` 로 선언해 "뒤에 온 쪽이 이기는" 상황을 만들었기 때문이다.
30
+ * 특이도 0 으로 선언하면 그 방어가 통째로 필요 없어진다.
31
+ *
32
+ * ──────────────────────────────────────────────────────────────────────────
33
+ * 이 프리셋이 정하는 것 / 정하지 않는 것
34
+ * ──────────────────────────────────────────────────────────────────────────
35
+ * 정한다 타이포 스케일 값 · 형태(반경) · 엘리베이션 · 여백 리듬
36
+ * 안 정한다 **중립 램프의 색조(웜/쿨)** — 역할 토큰 다수가 중립에서 파생되므로 램프를
37
+ * 옮기면 대비가 함께 움직인다. 전수 대비 검증을 붙이기 전에는 손대지 않는다.
38
+ * (LOB 화면에서 "낡아 보임"의 지분은 타이포·여백·형태가 훨씬 크다.)
39
+ * 안 정한다 **브랜드 색** — 그것은 소비앱의 몫이다. 프리셋은 브랜드를 갖지 않는다.
40
+ * ========================================================================== */
41
+
42
+ :where(:root) {
43
+ /* ==========================================================================
44
+ 타이포 — LOB 밀도
45
+ ★업무 화면은 한 화면에 담기는 정보량이 곧 생산성이다. 중립 기본값보다 한 단씩
46
+ 조밀하게 잡되, **행간은 줄이지 않는다**(한글에서 행간을 줄이면 바로 읽기 어려워진다).
47
+ 자간은 큰 제목만 음수이고 나머지는 0 — 한글에 양수 자간을 주지 않는다.
48
+ ========================================================================== */
49
+ --u-text-display-size: 24px;
50
+ --u-text-display-weight: 700;
51
+ --u-text-display-leading: 1.4;
52
+ --u-text-display-tracking: -0.02em;
53
+
54
+ --u-text-title-size: 18px;
55
+ --u-text-title-weight: 700;
56
+ --u-text-title-leading: 1.45;
57
+ --u-text-title-tracking: -0.01em;
58
+
59
+ --u-text-subtitle-size: 15px;
60
+ --u-text-subtitle-weight: 600;
61
+ --u-text-subtitle-leading: 1.5;
62
+ --u-text-subtitle-tracking: 0;
63
+
64
+ --u-text-body-size: 14px;
65
+ --u-text-body-weight: 400;
66
+ --u-text-body-leading: 1.6;
67
+ --u-text-body-tracking: 0;
68
+
69
+ /* ★라벨 단이 이 프리셋에서 가장 많이 쓰인다 — 폼 라벨·표 머리행·섹션 제목이 전부
70
+ 이 단이다. 한글에 대문자가 없으므로 위계는 **크기·굵기·색** 세 신호로만 만든다. */
71
+ --u-text-label-size: 13px;
72
+ --u-text-label-weight: 600;
73
+ --u-text-label-leading: 1.5;
74
+ --u-text-label-tracking: 0;
75
+
76
+ --u-text-caption-size: 12px;
77
+ --u-text-caption-weight: 400;
78
+ --u-text-caption-leading: 1.5;
79
+ --u-text-caption-tracking: 0;
80
+
81
+ /* ⚠양수 자간은 이 단 하나뿐이고, 이 단은 **영문·숫자 라벨**을 전제한다.
82
+ 한글을 넣을 소비자는 `--u-text-overline-tracking: 0` 으로 덮는다. */
83
+ --u-text-overline-size: 11px;
84
+ --u-text-overline-weight: 700;
85
+ --u-text-overline-leading: 1.45;
86
+ --u-text-overline-tracking: 0.06em;
87
+
88
+ /* ==========================================================================
89
+ 형태 — 반경
90
+ ★컨트롤 단(sm~xl)을 한 단씩 올린다. 중립 기본값(3/4/6/8)은 어떤 값을 골라도
91
+ 각진 인상이 되는데, 각짐은 "낡아 보임"에 대한 기여가 큰 축이다.
92
+ 면(surface) 단(2xl·3xl)은 중립 기본값과 같다 — 이미 적절하다.
93
+ ========================================================================== */
94
+ --u-radius-sm: 4px;
95
+ --u-radius-md: 6px;
96
+ --u-radius-lg: 8px;
97
+ --u-radius-xl: 10px;
98
+
99
+ /* ==========================================================================
100
+ 엘리베이션 — 청흑 틴트
101
+ ★순수 검정 그림자는 경계에 회색이 낀 것처럼 보인다. 배경의 색조를 살짝 섞은
102
+ 어두운 값(`20,20,25`)을 쓰면 같은 세기라도 깨끗하게 떨어진다.
103
+ 2겹 구조(지배 + 접촉)는 `components` 가 이미 정했고, 여기서는 **색만** 바꾼다.
104
+ ⚠첫 레이어가 지배 레이어라는 배치 규약을 유지한다(`components` 의 elevation 계약).
105
+ ========================================================================== */
106
+ --u-shadow-color-weaker: rgba(20, 20, 25, 0.04);
107
+ --u-shadow-color-weak: rgba(20, 20, 25, 0.08);
108
+ --u-shadow-color-normal: rgba(20, 20, 25, 0.10);
109
+ --u-shadow-color-strong: rgba(20, 20, 25, 0.14);
110
+ --u-shadow-color-stronger: rgba(20, 20, 25, 0.20);
111
+
112
+ --u-shadow-sm: 0 1px 3px rgba(20, 20, 25, 0.08), 0 1px 1px rgba(20, 20, 25, 0.04);
113
+ --u-shadow-md: 0 2px 8px rgba(20, 20, 25, 0.10), 0 1px 2px rgba(20, 20, 25, 0.04);
114
+ --u-shadow-lg: 0 6px 16px rgba(20, 20, 25, 0.14), 0 2px 4px rgba(20, 20, 25, 0.05);
115
+ --u-shadow-xl: 0 12px 28px rgba(20, 20, 25, 0.20), 0 2px 6px rgba(20, 20, 25, 0.06);
116
+ }
117
+
118
+ /*
119
+ * 다크 — 그림자는 **밝기 차**가 주역이다.
120
+ * ★어두운 배경 위의 검은 그림자는 보이지 않는다. 알파를 라이트보다 크게 잡되,
121
+ * 깊이의 대부분은 표면 밝기 차(`--u-bg-color-raised` 등, `components` 소유)가 낸다.
122
+ */
123
+ :where(:root[theme='dark']) {
124
+ --u-shadow-color-weaker: rgba(0, 0, 0, 0.20);
125
+ --u-shadow-color-weak: rgba(0, 0, 0, 0.28);
126
+ --u-shadow-color-normal: rgba(0, 0, 0, 0.36);
127
+ --u-shadow-color-strong: rgba(0, 0, 0, 0.46);
128
+ --u-shadow-color-stronger: rgba(0, 0, 0, 0.60);
129
+
130
+ --u-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.28), 0 1px 1px rgba(0, 0, 0, 0.16);
131
+ --u-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.36), 0 1px 2px rgba(0, 0, 0, 0.18);
132
+ --u-shadow-lg: 0 6px 16px rgba(0, 0, 0, 0.46), 0 2px 4px rgba(0, 0, 0, 0.22);
133
+ --u-shadow-xl: 0 12px 28px rgba(0, 0, 0, 0.60), 0 2px 6px rgba(0, 0, 0, 0.30);
134
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/enterprise",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Enterprise utilities and components for iyulab framework",
5
5
  "keywords": [
6
6
  "enterprise",
@@ -25,17 +25,15 @@
25
25
  ".": {
26
26
  "types": "./dist/index.d.ts",
27
27
  "import": "./dist/index.js"
28
- }
28
+ },
29
+ "./styles/preset.css": "./dist/styles/preset.css"
29
30
  },
30
31
  "scripts": {
31
- "build": "vite build",
32
+ "build": "vite build && node scripts/copy-styles.mjs",
32
33
  "test": "vitest run"
33
34
  },
34
35
  "dependencies": {
35
- "@iyulab/components": "^1.8.0",
36
- "@iyulab/data-components": "^0.7.0",
37
36
  "@iyulab/http-client": "^0.10.0",
38
- "@iyulab/modern-app": "^0.6.0",
39
37
  "odata-query": "^8.1.0"
40
38
  },
41
39
  "devDependencies": {
@@ -44,5 +42,14 @@
44
42
  "vite": "^8.1.4",
45
43
  "vite-plugin-dts": "^5.0.3",
46
44
  "vitest": "^4.1.10"
45
+ },
46
+ "peerDependencies": {
47
+ "react": ">=18",
48
+ "@iyulab/components": ">=1.21.0"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "@iyulab/components": {
52
+ "optional": true
53
+ }
47
54
  }
48
55
  }