@tcn/ui 0.0.4 → 0.1.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.
Files changed (107) hide show
  1. package/dist/actions/button/base_button/base_button.d.ts.map +1 -1
  2. package/dist/actions/button/base_button/base_button.js +17 -12
  3. package/dist/actions/button/base_button/base_button.js.map +1 -1
  4. package/dist/actions/button/button/button.d.ts.map +1 -1
  5. package/dist/actions/button/button/button.js +7 -7
  6. package/dist/actions/button/button/button.js.map +1 -1
  7. package/dist/actions/button/slim_button/slim_button.js +2 -2
  8. package/dist/actions/button/slim_button/slim_button.js.map +1 -1
  9. package/dist/button.css +1 -1
  10. package/dist/footer.css +1 -1
  11. package/dist/form/field/common/field_error.js +3 -2
  12. package/dist/form/field/common/field_error.js.map +1 -1
  13. package/dist/inputs/input/input.d.ts +2 -2
  14. package/dist/inputs/input/input.d.ts.map +1 -1
  15. package/dist/inputs/input/input.js.map +1 -1
  16. package/dist/inputs/options/option.d.ts +1 -0
  17. package/dist/inputs/options/option.d.ts.map +1 -1
  18. package/dist/inputs/options/option.js.map +1 -1
  19. package/dist/inputs/phone_number_input/phone_number_input.d.ts +6 -1
  20. package/dist/inputs/phone_number_input/phone_number_input.d.ts.map +1 -1
  21. package/dist/inputs/phone_number_input/phone_number_input.js +169 -125
  22. package/dist/inputs/phone_number_input/phone_number_input.js.map +1 -1
  23. package/dist/inputs/suggestions/suggestion_item.d.ts +1 -1
  24. package/dist/inputs/suggestions/suggestion_item.d.ts.map +1 -1
  25. package/dist/inputs/suggestions/suggestion_item.js +23 -18
  26. package/dist/inputs/suggestions/suggestion_item.js.map +1 -1
  27. package/dist/inputs/suggestions/suggestion_list.d.ts +1 -1
  28. package/dist/inputs/suggestions/suggestion_list.d.ts.map +1 -1
  29. package/dist/inputs/suggestions/suggestion_list.js +105 -95
  30. package/dist/inputs/suggestions/suggestion_list.js.map +1 -1
  31. package/dist/layouts/footer/footer.js +5 -5
  32. package/dist/layouts/footer/footer.js.map +1 -1
  33. package/dist/layouts/index.d.ts +3 -2
  34. package/dist/layouts/index.d.ts.map +1 -1
  35. package/dist/layouts/index.js +26 -24
  36. package/dist/layouts/index.js.map +1 -1
  37. package/dist/layouts/list/item.d.ts +1 -0
  38. package/dist/layouts/list/item.d.ts.map +1 -1
  39. package/dist/layouts/list/item.js +17 -6
  40. package/dist/layouts/list/item.js.map +1 -1
  41. package/dist/layouts/list/list.js +10 -10
  42. package/dist/layouts/list/list.js.map +1 -1
  43. package/dist/overlay/context_menu/context_menu.js +4 -4
  44. package/dist/overlay/index.js +3 -3
  45. package/dist/overlay/popper/popper.js +12 -12
  46. package/dist/{portal-qqIp4SIl.js → overlay/portal/portal.js} +3 -3
  47. package/dist/overlay/portal/portal.js.map +1 -0
  48. package/dist/overlay/portal/portal_platform.js +3 -4
  49. package/dist/overlay/portal/portal_platform.js.map +1 -1
  50. package/dist/phone_number_input.css +1 -1
  51. package/dist/slim_button.css +1 -1
  52. package/dist/surfaces/card/card.d.ts.map +1 -1
  53. package/dist/surfaces/card/card.js +7 -16
  54. package/dist/surfaces/card/card.js.map +1 -1
  55. package/dist/surfaces/confirm/confirm.js +4 -4
  56. package/dist/themes/index.js +6 -141
  57. package/dist/themes/index.js.map +1 -1
  58. package/dist/themes/stylesheets/reset.js +140 -0
  59. package/dist/themes/stylesheets/reset.js.map +1 -0
  60. package/dist/themes/themes/ergo/ergo_theme.js +595 -0
  61. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -0
  62. package/dist/tokens/bubble/bubble.js +17 -16
  63. package/dist/tokens/bubble/bubble.js.map +1 -1
  64. package/dist/tokens/chip/chip.js +9 -8
  65. package/dist/tokens/chip/chip.js.map +1 -1
  66. package/dist/typography/title/title.js +8 -8
  67. package/dist/typography/title/title.js.map +1 -1
  68. package/package.json +3 -3
  69. package/src/actions/button/base_button/base_button.tsx +7 -2
  70. package/src/actions/button/button/button.module.css +0 -78
  71. package/src/actions/button/button/button.tsx +2 -4
  72. package/src/actions/button/slim_button/slim_button.module.css +0 -26
  73. package/src/actions/button/slim_button/slim_button.tsx +1 -1
  74. package/src/inputs/input/input.tsx +3 -2
  75. package/src/inputs/options/option.tsx +1 -0
  76. package/src/inputs/phone_number_input/phone_number_input.module.css +12 -0
  77. package/src/inputs/phone_number_input/phone_number_input.stories.tsx +8 -0
  78. package/src/inputs/phone_number_input/phone_number_input.tsx +99 -21
  79. package/src/inputs/suggestions/suggestion_item.tsx +12 -2
  80. package/src/inputs/suggestions/suggestion_list.tsx +22 -3
  81. package/src/layouts/footer/footer.module.css +0 -1
  82. package/src/layouts/footer/footer.tsx +1 -1
  83. package/src/layouts/index.ts +3 -2
  84. package/src/layouts/list/item.tsx +10 -2
  85. package/src/layouts/list/list.tsx +2 -2
  86. package/src/surfaces/card/card.tsx +2 -8
  87. package/src/surfaces/modal/__stories__/modal.stories.tsx +1 -1
  88. package/src/surfaces/panel/__stories__/panel.stories.tsx +13 -12
  89. package/src/themes/themes/ergo/__stories__/components/material_picker/sb_inverted_materials.module.css +34 -0
  90. package/src/themes/themes/ergo/__stories__/components/material_picker/sb_material_picker.tsx +52 -0
  91. package/src/themes/themes/ergo/__stories__/components/tone_picker/sb_card.module.css +5 -0
  92. package/src/themes/themes/ergo/__stories__/components/tone_picker/sb_tone_card.tsx +40 -0
  93. package/src/themes/themes/ergo/__stories__/components/tone_picker/sb_tone_picker.tsx +83 -0
  94. package/src/themes/themes/ergo/__stories__/components/tone_picker/types.ts +7 -0
  95. package/src/themes/themes/ergo/__stories__/material.stories.tsx +154 -0
  96. package/src/themes/themes/ergo/__stories__/sb_materials.module.css +110 -0
  97. package/src/themes/themes/ergo/__stories__/utils.ts +92 -0
  98. package/src/themes/themes/ergo/ergo_theme.css +298 -35
  99. package/src/typography/title/title.tsx +1 -1
  100. package/tsconfig.json +0 -3
  101. package/dist/card.css +0 -1
  102. package/dist/portal-qqIp4SIl.js.map +0 -1
  103. package/dist/themes/stylesheets/reset.css +0 -1
  104. package/dist/themes/themes/ergo/ergo_theme.css +0 -1
  105. package/dist/themes/themes/windows_98/windows_98.css +0 -1
  106. package/src/surfaces/card/card.module.css +0 -5
  107. /package/dist/{overlay/portal/portal.css → portal_platform.css} +0 -0
@@ -1,15 +1,16 @@
1
- import { jsx as p } from "react/jsx-runtime";
2
- import { HStack as m } from "../../stacks/h_stack.js";
1
+ import { jsx as m } from "react/jsx-runtime";
2
+ import { HStack as n } from "../../stacks/h_stack.js";
3
3
  import { clsx as f } from "clsx";
4
4
  import h from "react";
5
5
  import { theme as s } from "../../themes/theme_variables.js";
6
- import '../../chip.css';const l = "_chip_35f6f0b", a = { chip: l }, w = h.forwardRef(function({ children: t, style: o, className: i, color: r = s.accentColor, ...c }, e) {
7
- const n = {
6
+ import "../../themes/stylesheets/reset.js";
7
+ import '../../chip.css';const l = "_chip_35f6f0b", a = { chip: l }, R = h.forwardRef(function({ children: t, style: o, className: i, color: r = s.accentColor, ...c }, e) {
8
+ const p = {
8
9
  "--chip-color": r,
9
10
  ...o
10
11
  };
11
- return /* @__PURE__ */ p(
12
- m,
12
+ return /* @__PURE__ */ m(
13
+ n,
13
14
  {
14
15
  ref: e,
15
16
  inline: !0,
@@ -17,13 +18,13 @@ import '../../chip.css';const l = "_chip_35f6f0b", a = { chip: l }, w = h.forwar
17
18
  height: "auto",
18
19
  vAlign: "center",
19
20
  className: f(a.chip, "chip", i),
20
- style: n,
21
+ style: p,
21
22
  ...c,
22
23
  children: t
23
24
  }
24
25
  );
25
26
  });
26
27
  export {
27
- w as Chip
28
+ R as Chip
28
29
  };
29
30
  //# sourceMappingURL=chip.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chip.js","sources":["../../../src/tokens/chip/chip.tsx"],"sourcesContent":["import { HStack, HStackProps } from '../../stacks/h_stack.js';\nimport { clsx } from 'clsx';\nimport React from 'react';\nimport styles from './chip.module.css';\nimport { theme } from '../../themes/index.js';\n\nexport interface ChipProps extends HStackProps {\n children?: React.ReactNode;\n color?: string;\n disabled?: boolean;\n}\n\nexport const Chip = React.forwardRef(function Chip(\n { children, style, className, color = theme.accentColor, ...props }: ChipProps,\n ref: React.Ref<HTMLDivElement>\n) {\n const finalStyle = {\n '--chip-color': color,\n ...style,\n };\n\n return (\n <HStack\n ref={ref}\n inline\n width=\"auto\"\n height=\"auto\"\n vAlign=\"center\"\n className={clsx(styles.chip, 'chip', className)}\n style={finalStyle}\n {...props}\n >\n {children}\n </HStack>\n );\n});\n"],"names":["Chip","React","children","style","className","color","theme","props","ref","finalStyle","jsx","HStack","clsx","styles"],"mappings":";;;;;4CAYaA,IAAOC,EAAM,WAAW,SACnC,EAAE,UAAAC,GAAU,OAAAC,GAAO,WAAAC,GAAW,OAAAC,IAAQC,EAAM,aAAa,GAAGC,EAAA,GAC5DC,GACA;AACA,QAAMC,IAAa;AAAA,IACjB,gBAAgBJ;AAAA,IAChB,GAAGF;AAAA,EAAA;AAGL,SACE,gBAAAO;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,KAAAH;AAAA,MACA,QAAM;AAAA,MACN,OAAM;AAAA,MACN,QAAO;AAAA,MACP,QAAO;AAAA,MACP,WAAWI,EAAKC,EAAO,MAAM,QAAQT,CAAS;AAAA,MAC9C,OAAOK;AAAA,MACN,GAAGF;AAAA,MAEH,UAAAL;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;"}
1
+ {"version":3,"file":"chip.js","sources":["../../../src/tokens/chip/chip.tsx"],"sourcesContent":["import { HStack, HStackProps } from '../../stacks/h_stack.js';\nimport { clsx } from 'clsx';\nimport React from 'react';\nimport styles from './chip.module.css';\nimport { theme } from '../../themes/index.js';\n\nexport interface ChipProps extends HStackProps {\n children?: React.ReactNode;\n color?: string;\n disabled?: boolean;\n}\n\nexport const Chip = React.forwardRef(function Chip(\n { children, style, className, color = theme.accentColor, ...props }: ChipProps,\n ref: React.Ref<HTMLDivElement>\n) {\n const finalStyle = {\n '--chip-color': color,\n ...style,\n };\n\n return (\n <HStack\n ref={ref}\n inline\n width=\"auto\"\n height=\"auto\"\n vAlign=\"center\"\n className={clsx(styles.chip, 'chip', className)}\n style={finalStyle}\n {...props}\n >\n {children}\n </HStack>\n );\n});\n"],"names":["Chip","React","children","style","className","color","theme","props","ref","finalStyle","jsx","HStack","clsx","styles"],"mappings":";;;;;;4CAYaA,IAAOC,EAAM,WAAW,SACnC,EAAE,UAAAC,GAAU,OAAAC,GAAO,WAAAC,GAAW,OAAAC,IAAQC,EAAM,aAAa,GAAGC,EAAA,GAC5DC,GACA;AACA,QAAMC,IAAa;AAAA,IACjB,gBAAgBJ;AAAA,IAChB,GAAGF;AAAA,EAAA;AAGL,SACE,gBAAAO;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,KAAAH;AAAA,MACA,QAAM;AAAA,MACN,OAAM;AAAA,MACN,QAAO;AAAA,MACP,QAAO;AAAA,MACP,WAAWI,EAAKC,EAAO,MAAM,QAAQT,CAAS;AAAA,MAC9C,OAAOK;AAAA,MACN,GAAGF;AAAA,MAEH,UAAAL;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;"}
@@ -4,30 +4,30 @@ import { s as x } from "../../title.module-B16de2jd.js";
4
4
  function A({
5
5
  size: a = "md",
6
6
  emphasis: o = "normal",
7
- hierarchy: c = "primary",
7
+ hierarchy: p = "primary",
8
8
  color: n,
9
- children: g,
10
- className: h,
9
+ children: c,
10
+ className: g,
11
11
  style: i = {},
12
12
  padStart: r,
13
13
  padEnd: e,
14
14
  padBottom: f,
15
15
  padTop: l,
16
16
  pad: m,
17
- selectable: p = !0,
17
+ selectable: h = !0,
18
18
  as: d
19
19
  }) {
20
20
  let t = d;
21
21
  return d == null && (a === "lg" ? t = "h1" : a === "md" ? t = "h2" : t = "h3"), m && (i.padding = m), r && (i.paddingInlineStart = r), e && (i.paddingInlineEnd = e), l && (i.paddingTop = l), f && (i.paddingBottom = f), n && (i.color = n), /* @__PURE__ */ s(
22
22
  t,
23
23
  {
24
- "data-hierarchy": c,
24
+ "data-hierarchy": p,
25
25
  "data-emphasis": o,
26
- "data-selectable": p,
27
- className: u(x.title, "title", "tcn-title", h),
26
+ "data-selectable": h,
27
+ className: u(x.title, "title", "tcn-typography", "tcn-title", g),
28
28
  style: i,
29
29
  "data-size": a,
30
- children: g
30
+ children: c
31
31
  }
32
32
  );
33
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"title.js","sources":["../../../src/typography/title/title.tsx"],"sourcesContent":["import React from 'react';\nimport { clsx } from 'clsx';\nimport type { WithDetailedHTMLProps } from '../../stacks/types/as.js';\nimport type { Emphasis, Hierarchy, Size } from '../../utils/index.js';\nimport styles from './title.module.css';\n\nexport interface TitleOwnProps {\n children?: string;\n size?: Size;\n emphasis?: Emphasis;\n hierarchy?: Hierarchy;\n color?: string;\n pad?: string;\n padStart?: string;\n padEnd?: string;\n padTop?: string;\n padBottom?: string;\n selectable?: boolean;\n as?: string;\n}\n\nexport type TitleProps = WithDetailedHTMLProps<TitleOwnProps, 'h1' | 'h2' | 'h3'>;\n\nexport function Title({\n size = 'md',\n emphasis = 'normal',\n hierarchy = 'primary',\n color,\n children,\n className,\n style = {},\n padStart,\n padEnd,\n padBottom,\n padTop,\n pad,\n selectable = true,\n as,\n}: TitleProps) {\n let As: React.ElementType = as as React.ElementType;\n\n if (as == null) {\n if (size === 'lg') {\n As = 'h1';\n } else if (size === 'md') {\n As = 'h2';\n } else {\n As = 'h3';\n }\n }\n\n if (pad) {\n style.padding = pad;\n }\n\n if (padStart) {\n style.paddingInlineStart = padStart;\n }\n\n if (padEnd) {\n style.paddingInlineEnd = padEnd;\n }\n\n if (padTop) {\n style.paddingTop = padTop;\n }\n\n if (padBottom) {\n style.paddingBottom = padBottom;\n }\n\n if (color) {\n style.color = color;\n }\n\n return (\n <As\n data-hierarchy={hierarchy}\n data-emphasis={emphasis}\n data-selectable={selectable}\n className={clsx(styles['title'], 'title', 'tcn-title', className)}\n style={style}\n data-size={size}\n >\n {children}\n </As>\n );\n}\n"],"names":["Title","size","emphasis","hierarchy","color","children","className","style","padStart","padEnd","padBottom","padTop","pad","selectable","as","As","jsx","clsx","styles"],"mappings":";;;AAuBO,SAASA,EAAM;AAAA,EACpB,MAAAC,IAAO;AAAA,EACP,UAAAC,IAAW;AAAA,EACX,WAAAC,IAAY;AAAA,EACZ,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,WAAAC;AAAA,EACA,OAAAC,IAAQ,CAAA;AAAA,EACR,UAAAC;AAAA,EACA,QAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,KAAAC;AAAA,EACA,YAAAC,IAAa;AAAA,EACb,IAAAC;AACF,GAAe;AACb,MAAIC,IAAwBD;AAE5B,SAAIA,KAAM,SACJb,MAAS,OACXc,IAAK,OACId,MAAS,OAClBc,IAAK,OAELA,IAAK,OAILH,MACFL,EAAM,UAAUK,IAGdJ,MACFD,EAAM,qBAAqBC,IAGzBC,MACFF,EAAM,mBAAmBE,IAGvBE,MACFJ,EAAM,aAAaI,IAGjBD,MACFH,EAAM,gBAAgBG,IAGpBN,MACFG,EAAM,QAAQH,IAId,gBAAAY;AAAA,IAACD;AAAA,IAAA;AAAA,MACC,kBAAgBZ;AAAA,MAChB,iBAAeD;AAAA,MACf,mBAAiBW;AAAA,MACjB,WAAWI,EAAKC,EAAO,OAAU,SAAS,aAAaZ,CAAS;AAAA,MAChE,OAAAC;AAAA,MACA,aAAWN;AAAA,MAEV,UAAAI;AAAA,IAAA;AAAA,EAAA;AAGP;"}
1
+ {"version":3,"file":"title.js","sources":["../../../src/typography/title/title.tsx"],"sourcesContent":["import React from 'react';\nimport { clsx } from 'clsx';\nimport type { WithDetailedHTMLProps } from '../../stacks/types/as.js';\nimport type { Emphasis, Hierarchy, Size } from '../../utils/index.js';\nimport styles from './title.module.css';\n\nexport interface TitleOwnProps {\n children?: string;\n size?: Size;\n emphasis?: Emphasis;\n hierarchy?: Hierarchy;\n color?: string;\n pad?: string;\n padStart?: string;\n padEnd?: string;\n padTop?: string;\n padBottom?: string;\n selectable?: boolean;\n as?: string;\n}\n\nexport type TitleProps = WithDetailedHTMLProps<TitleOwnProps, 'h1' | 'h2' | 'h3'>;\n\nexport function Title({\n size = 'md',\n emphasis = 'normal',\n hierarchy = 'primary',\n color,\n children,\n className,\n style = {},\n padStart,\n padEnd,\n padBottom,\n padTop,\n pad,\n selectable = true,\n as,\n}: TitleProps) {\n let As: React.ElementType = as as React.ElementType;\n\n if (as == null) {\n if (size === 'lg') {\n As = 'h1';\n } else if (size === 'md') {\n As = 'h2';\n } else {\n As = 'h3';\n }\n }\n\n if (pad) {\n style.padding = pad;\n }\n\n if (padStart) {\n style.paddingInlineStart = padStart;\n }\n\n if (padEnd) {\n style.paddingInlineEnd = padEnd;\n }\n\n if (padTop) {\n style.paddingTop = padTop;\n }\n\n if (padBottom) {\n style.paddingBottom = padBottom;\n }\n\n if (color) {\n style.color = color;\n }\n\n return (\n <As\n data-hierarchy={hierarchy}\n data-emphasis={emphasis}\n data-selectable={selectable}\n className={clsx(styles['title'], 'title', 'tcn-typography', 'tcn-title', className)}\n style={style}\n data-size={size}\n >\n {children}\n </As>\n );\n}\n"],"names":["Title","size","emphasis","hierarchy","color","children","className","style","padStart","padEnd","padBottom","padTop","pad","selectable","as","As","jsx","clsx","styles"],"mappings":";;;AAuBO,SAASA,EAAM;AAAA,EACpB,MAAAC,IAAO;AAAA,EACP,UAAAC,IAAW;AAAA,EACX,WAAAC,IAAY;AAAA,EACZ,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,WAAAC;AAAA,EACA,OAAAC,IAAQ,CAAA;AAAA,EACR,UAAAC;AAAA,EACA,QAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,KAAAC;AAAA,EACA,YAAAC,IAAa;AAAA,EACb,IAAAC;AACF,GAAe;AACb,MAAIC,IAAwBD;AAE5B,SAAIA,KAAM,SACJb,MAAS,OACXc,IAAK,OACId,MAAS,OAClBc,IAAK,OAELA,IAAK,OAILH,MACFL,EAAM,UAAUK,IAGdJ,MACFD,EAAM,qBAAqBC,IAGzBC,MACFF,EAAM,mBAAmBE,IAGvBE,MACFJ,EAAM,aAAaI,IAGjBD,MACFH,EAAM,gBAAgBG,IAGpBN,MACFG,EAAM,QAAQH,IAId,gBAAAY;AAAA,IAACD;AAAA,IAAA;AAAA,MACC,kBAAgBZ;AAAA,MAChB,iBAAeD;AAAA,MACf,mBAAiBW;AAAA,MACjB,WAAWI,EAAKC,EAAO,OAAU,SAAS,kBAAkB,aAAaZ,CAAS;AAAA,MAClF,OAAAC;AAAA,MACA,aAAWN;AAAA,MAEV,UAAAI;AAAA,IAAA;AAAA,EAAA;AAGP;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tcn/ui",
3
- "version": "0.0.4",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "author": "TCN",
@@ -128,8 +128,8 @@
128
128
  "dependencies": {
129
129
  "clsx": "^2.1.1",
130
130
  "react-color": "^2.19.3",
131
- "@tcn/state": "1.0.0",
132
- "@tcn/icons": "2.1.0"
131
+ "@tcn/icons": "2.1.1",
132
+ "@tcn/state": "1.0.1"
133
133
  },
134
134
  "scripts": {
135
135
  "build": "vite build",
@@ -27,7 +27,7 @@ export const BaseButton = React.forwardRef<HTMLButtonElement, BaseButtonProps>(
27
27
  style,
28
28
  color,
29
29
  hierarchy = 'secondary',
30
- size = 'medium',
30
+ size = 'md',
31
31
  onTouchStart,
32
32
  onContextMenu,
33
33
  ...props
@@ -68,7 +68,12 @@ export const BaseButton = React.forwardRef<HTMLButtonElement, BaseButtonProps>(
68
68
  data-hierarchy={hierarchy}
69
69
  data-size={size}
70
70
  data-is-disabled={Boolean(props.disabled)}
71
- className={clsx(styles['base-button'], 'base-button', className)}
71
+ className={clsx(
72
+ styles['base-button'],
73
+ 'tcn-interactive',
74
+ 'tcn-base-button',
75
+ className
76
+ )}
72
77
  style={finalStyle}
73
78
  onTouchStart={handleTouchStart}
74
79
  onContextMenu={handleContextMenu}
@@ -6,90 +6,12 @@
6
6
  --button-color-disabled: var(--status-disabled, #cccccc);
7
7
 
8
8
  min-height: var(--button-height);
9
- padding: 4px 8px;
10
- border-radius: 4px;
11
9
  width: auto;
12
- border: 1px solid transparent;
13
- outline: none;
14
10
  cursor: pointer;
15
- background: transparent;
16
11
  font-size: calc(14px * var(--scalar, 1));
17
12
  line-height: calc(16px * var(--scalar, 1));
18
13
  }
19
14
 
20
- .button:focus-visible {
21
- outline: 3px solid color-mix(in srgb, var(--button-color) 40%, transparent);
22
- }
23
-
24
- /* Primary */
25
- .button[data-hierarchy="primary"] {
26
- background: var(--button-color);
27
- color: #ffffff;
28
- }
29
-
30
- .button[data-hierarchy="primary"]:hover {
31
- background: var(--button-color-hover);
32
- color: #ffffff;
33
- }
34
-
35
- .button[data-hierarchy="primary"]:active {
36
- background: var(--button-color-active);
37
- box-shadow: none;
38
- }
39
-
40
- /* Secondary */
41
- .button[data-hierarchy="secondary"] {
42
- color: rgb(57, 85, 120);
43
- border-color: rgb(57, 85, 120);
44
- }
45
-
46
- .button[data-hierarchy="secondary"]:hover {
47
- background: color-mix(in srgb, rgb(57, 85, 120) 10%, rgb(255, 255, 255, 0.5));
48
- }
49
-
50
- .button[data-hierarchy="secondary"]:active {
51
- background: color-mix(in srgb, rgb(57, 85, 120) 25%, rgb(255, 255, 255, 0.5));
52
- }
53
-
54
- /* Tertiary */
55
- .button[data-hierarchy="tertiary"] {
56
- border-color: transparent;
57
- color: rgb(57, 85, 120);
58
- }
59
-
60
- .button[data-hierarchy="tertiary"]:hover {
61
- text-decoration: underline;
62
- text-decoration-color: rgb(57, 85, 120);
63
- text-decoration-thickness: 1px;
64
- text-underline-offset: 2px;
65
- }
66
-
67
- .button[data-hierarchy="tertiary"]:active {
68
- opacity: 0.5;
69
- }
70
-
71
- /* Disabled */
72
- .button[data-is-disabled="true"] {
73
- pointer-events: none;
74
- background: var(--button-color-disabled);
75
- color: #ffffff;
76
- border-color: var(--button-color-disabled);
77
- }
78
-
79
- /* Disabled Secondary */
80
- .button[data-hierarchy="secondary"][data-is-disabled="true"] {
81
- background: transparent;
82
- color: var(--button-color-disabled);
83
- border-color: var(--button-color-disabled);
84
- }
85
-
86
- /* Disabled Tertiary */
87
- .button[data-hierarchy="tertiary"][data-is-disabled="true"] {
88
- background: transparent;
89
- color: var(--button-color-disabled);
90
- border-color: transparent;
91
- }
92
-
93
15
  /* Sizes */
94
16
  .button[data-size="sm"] {
95
17
  --button-height: calc(22px * var(--scalar, 1));
@@ -12,13 +12,11 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(function
12
12
  return (
13
13
  <BaseButton
14
14
  ref={ref}
15
- className={clsx(styles.button, 'button', 'tcn-button', className)}
15
+ className={clsx(styles.button, 'tcn-button', className)}
16
16
  {...props}
17
17
  >
18
18
  {typeof children === 'string' ? (
19
- <span className={clsx(styles['button-text'], 'button-text', 'tcn-button-text')}>
20
- {children}
21
- </span>
19
+ <span className={clsx(styles['button-text'], 'tcn-button-text')}>{children}</span>
22
20
  ) : (
23
21
  children
24
22
  )}
@@ -5,29 +5,3 @@
5
5
  .slim-button[data-is-disabled="true"] {
6
6
  pointer-events: none;
7
7
  }
8
-
9
- .slim-button[data-size="sm"] {
10
- padding: 1px;
11
- }
12
-
13
- .slim-button[data-size="md"] {
14
- padding: 2px;
15
- }
16
-
17
- .slim-button[data-size="lg"] {
18
- padding: 3px;
19
- }
20
-
21
- .slim-button[data-hierarchy="tertiary"][data-is-disabled="true"] {
22
- background-color: transparent;
23
- border: none;
24
- color: var(--button-color-disabled);
25
- min-height: auto;
26
- pointer-events: none;
27
- }
28
-
29
- .slim-button[data-hierarchy="secondary"][data-is-disabled="true"] {
30
- background-color: transparent;
31
- border: 1px solid var(--button-color-disabled);
32
- color: var(--button-color-disabled);
33
- }
@@ -9,7 +9,7 @@ export const SlimButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
9
9
  return (
10
10
  <Button
11
11
  ref={ref}
12
- className={clsx(styles['slim-button'], 'slim-button', className)}
12
+ className={clsx(styles['slim-button'], 'tcn-slim-button', className)}
13
13
  {...props}
14
14
  >
15
15
  {children}
@@ -1,9 +1,10 @@
1
1
  import { clsx } from 'clsx';
2
2
  import React from 'react';
3
- import { HTMLAttributes } from 'react';
3
+ import { InputHTMLAttributes } from 'react';
4
4
  import styles from './input.module.css';
5
5
 
6
- export interface InputProps extends Omit<HTMLAttributes<HTMLInputElement>, 'onChange'> {
6
+ export interface InputProps
7
+ extends Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
7
8
  type?: React.HTMLInputTypeAttribute;
8
9
  width?: string;
9
10
  height?: string;
@@ -9,6 +9,7 @@ export interface OptionProps {
9
9
  keywords?: string[];
10
10
  selected?: boolean;
11
11
  disabled?: boolean;
12
+ obfuscate?: boolean;
12
13
  }
13
14
 
14
15
  export function Option({ children }: OptionProps) {
@@ -48,3 +48,15 @@
48
48
  max-height: calc(26px * var(--scalar, 1)) !important;
49
49
  max-width: calc(26px * var(--scalar, 1)) !important;
50
50
  }
51
+
52
+ .phone-number-input-obfuscated {
53
+ user-select: none;
54
+ -webkit-user-select: none;
55
+ cursor: default;
56
+ width: 100%;
57
+ height: 100%;
58
+ }
59
+
60
+ .phone-number-input-obfuscated::selection {
61
+ background: transparent;
62
+ }
@@ -90,6 +90,14 @@ export function PhoneNumberInput() {
90
90
  >
91
91
  Bob Johnson - +1 (435) 586-5955
92
92
  </Option>
93
+ <Option
94
+ value="+14355865956"
95
+ label="Obfuscated Number"
96
+ keywords={['obfuscated', 'number']}
97
+ obfuscate={true}
98
+ >
99
+ Obfuscated Number
100
+ </Option>
93
101
  </Base>
94
102
  </td>
95
103
  </tr>
@@ -21,6 +21,16 @@ import { NotebookIcon } from '@tcn/icons/notebook_icon.js';
21
21
  import { Option, OptionProps } from '../options/option.js';
22
22
  import { SuggestionList } from '../suggestions/suggestion_list.js';
23
23
  import { stripNonNumericAfterCountryCode } from './utils.js';
24
+ import { useForkRef } from '../../utils/index.js';
25
+
26
+ const OBFUSCATED_CHARACTER = '•';
27
+
28
+ function createObfuscatedMasks(masks: { mask: string; placeholder?: string }[]) {
29
+ return masks.map(m => ({
30
+ ...m,
31
+ placeholder: m.mask.replace(/[9a*]/g, OBFUSCATED_CHARACTER),
32
+ }));
33
+ }
24
34
 
25
35
  const countryList = countriesPhoneInformation.map(i => ({
26
36
  name: i.name,
@@ -109,7 +119,12 @@ export interface PhoneNumberInputProps
109
119
  extends Omit<HStackProps, 'onChange' | 'children'> {
110
120
  value?: string;
111
121
  defaultCountry?: string;
112
- onChange?: (value: string) => void;
122
+ /**
123
+ * Callback fired when the phone number value changes.
124
+ * @param value - The phone number value with country prefix
125
+ * @param obfuscate - Whether the selected phone number is obfuscated (e.g., from a phone book entry marked as obfuscated)
126
+ */
127
+ onChange?: (value: string, obfuscate: boolean) => void;
113
128
  countrySelectRef?: React.Ref<HTMLButtonElement>;
114
129
  phoneNumberInputRef?: React.Ref<HTMLInputElement>;
115
130
  disabled?: boolean;
@@ -161,6 +176,10 @@ export const PhoneNumberInput = React.forwardRef(function PhoneNumberInput(
161
176
  const [currentMasks, setCurrentMasks] = useState([
162
177
  ...countriesPhoneInformation[0].masks,
163
178
  ]);
179
+ const [obfuscateValue, setObfuscateValue] = useState(false);
180
+ const [shouldFocusAfterClear, setShouldFocusAfterClear] = useState(false);
181
+ const internalInputRef = useRef<HTMLInputElement>(null);
182
+ const forkedInputRef = useForkRef(numberRef, internalInputRef);
164
183
 
165
184
  const countryOptions = useMemo(() => {
166
185
  return createCountryOptions(allowedCountryCodes);
@@ -183,7 +202,7 @@ export const PhoneNumberInput = React.forwardRef(function PhoneNumberInput(
183
202
 
184
203
  const value = `${countryInformation.prefix}${stripNonNumericAfterCountryCode(phoneNumber)}`;
185
204
  lastOutputValueRef.current = value;
186
- onChange && onChange(value);
205
+ onChange && onChange(value, false);
187
206
  }
188
207
 
189
208
  useLayoutEffect(() => {
@@ -202,9 +221,14 @@ export const PhoneNumberInput = React.forwardRef(function PhoneNumberInput(
202
221
  const lineNumber = stripNonNumericAfterCountryCode(newPhoneNumber);
203
222
  const outputValue = countryPrefix + lineNumber;
204
223
 
224
+ // Clear obfuscated state when user types manually
225
+ if (obfuscateValue) {
226
+ setObfuscateValue(false);
227
+ }
228
+
205
229
  lastOutputValueRef.current = outputValue;
206
230
  phoneNumber !== newPhoneNumber && setPhoneNumber(newPhoneNumber);
207
- onChange && onChange(outputValue);
231
+ onChange && onChange(outputValue, false);
208
232
  }
209
233
 
210
234
  function togglePhoneBook(e: React.MouseEvent<HTMLButtonElement>) {
@@ -219,9 +243,15 @@ export const PhoneNumberInput = React.forwardRef(function PhoneNumberInput(
219
243
  setPhoneBookElement(null);
220
244
  }
221
245
 
222
- function handlePhoneBookOptionSelect(value: string) {
246
+ function handlePhoneBookOptionSelect(
247
+ value: string,
248
+ _label: string | undefined,
249
+ _isSuggestion: boolean,
250
+ obfuscate: boolean
251
+ ) {
223
252
  // Update the phone number with the selected value
224
- updatePhoneNumber(value);
253
+ setObfuscateValue(obfuscate);
254
+ updatePhoneNumber(value, obfuscate);
225
255
  closePhoneBook();
226
256
  }
227
257
 
@@ -244,8 +274,22 @@ export const PhoneNumberInput = React.forwardRef(function PhoneNumberInput(
244
274
  return value;
245
275
  }
246
276
 
277
+ function handleObfuscatedInputChange(newValue: string) {
278
+ // When user types on a obfuscated input, clear the obfuscated state and start fresh
279
+ // The newValue will be the digits the user typed (mask filters to valid input)
280
+ setShouldFocusAfterClear(true);
281
+ setObfuscateValue(false);
282
+ setPhoneNumber(newValue);
283
+
284
+ const countryPrefix = countryCodeMap.get(countryCode)?.prefix;
285
+ const lineNumber = stripNonNumericAfterCountryCode(newValue);
286
+ const outputValue = countryPrefix + lineNumber;
287
+ lastOutputValueRef.current = outputValue;
288
+ onChange && onChange(outputValue, false);
289
+ }
290
+
247
291
  const updatePhoneNumber = useCallback(
248
- (value: string) => {
292
+ (value: string, obfuscate = false) => {
249
293
  const oldValue = lastOutputValueRef.current;
250
294
  const countryInformation = getCountryCodeFromValue(
251
295
  value,
@@ -259,7 +303,7 @@ export const PhoneNumberInput = React.forwardRef(function PhoneNumberInput(
259
303
 
260
304
  if (oldValue !== value) {
261
305
  setPhoneNumber(phoneNumber);
262
- onChange && onChange(value);
306
+ onChange && onChange(value, obfuscate);
263
307
  }
264
308
  },
265
309
  [defaultCountry, selectedCountry, onChange]
@@ -269,6 +313,14 @@ export const PhoneNumberInput = React.forwardRef(function PhoneNumberInput(
269
313
  updatePhoneNumber(value);
270
314
  }, [value, updatePhoneNumber]);
271
315
 
316
+ // Focus the input after transitioning from obfuscated to normal mode
317
+ useLayoutEffect(() => {
318
+ if (shouldFocusAfterClear && !obfuscateValue && internalInputRef.current) {
319
+ internalInputRef.current.focus();
320
+ setShouldFocusAfterClear(false);
321
+ }
322
+ }, [shouldFocusAfterClear, obfuscateValue]);
323
+
272
324
  return (
273
325
  <HStack
274
326
  ref={ref}
@@ -280,25 +332,51 @@ export const PhoneNumberInput = React.forwardRef(function PhoneNumberInput(
280
332
  className={clsx(styles['phone-number-input-select'], 'phone-number-input-select')}
281
333
  ref={countryRef}
282
334
  width="auto"
283
- value={countryCode}
335
+ value={obfuscateValue ? '' : countryCode}
284
336
  onChange={changeCountry}
285
- disabled={disabled}
286
- data-is-disabled={disabled}
337
+ disabled={disabled || obfuscateValue}
338
+ data-is-disabled={disabled || obfuscateValue}
339
+ data-is-obfuscated={obfuscateValue}
340
+ placeholder={obfuscateValue ? '––' : undefined}
287
341
  >
288
342
  {countryOptions}
289
343
  </Select>
290
344
  <HStack width="flex" className={clsx(styles['phone-number-input-container'])}>
291
- <MaskInput
292
- ref={numberRef}
293
- value={phoneNumber}
294
- mask={currentMasks}
295
- onChange={transformValue}
296
- disabled={disabled}
297
- data-is-disabled={disabled}
298
- data-has-phone-book={showPhoneBook}
299
- className={clsx(styles['phone-number-input'], 'phone-number-input')}
300
- preparePasteValue={preparePasteValue}
301
- />
345
+ {obfuscateValue ? (
346
+ <MaskInput
347
+ key="obfuscated"
348
+ ref={forkedInputRef}
349
+ value=""
350
+ mask={createObfuscatedMasks(currentMasks)}
351
+ onChange={handleObfuscatedInputChange}
352
+ disabled={disabled}
353
+ data-is-disabled={disabled}
354
+ data-has-phone-book={showPhoneBook}
355
+ data-is-obfuscated={true}
356
+ className={clsx(
357
+ styles['phone-number-input'],
358
+ styles['phone-number-input-obfuscated'],
359
+ 'phone-number-input'
360
+ )}
361
+ preparePasteValue={() => ''}
362
+ prepareCopyValue={() => ''}
363
+ prepareCutValue={() => ''}
364
+ />
365
+ ) : (
366
+ <MaskInput
367
+ key="normal"
368
+ ref={forkedInputRef}
369
+ value={phoneNumber}
370
+ mask={currentMasks}
371
+ onChange={transformValue}
372
+ disabled={disabled}
373
+ data-is-disabled={disabled}
374
+ data-has-phone-book={showPhoneBook}
375
+ data-is-obfuscated={false}
376
+ className={clsx(styles['phone-number-input'], 'phone-number-input')}
377
+ preparePasteValue={preparePasteValue}
378
+ />
379
+ )}
302
380
  </HStack>
303
381
  {showPhoneBook && (
304
382
  <>
@@ -6,7 +6,12 @@ export interface SuggestionItemProps {
6
6
  isFocused: boolean;
7
7
  isSelected: boolean;
8
8
  option: React.ReactElement;
9
- onClick?: (value: string, label: string, isSuggestion: boolean) => void;
9
+ onClick?: (
10
+ value: string,
11
+ label: string,
12
+ isSuggestion: boolean,
13
+ obfuscate: boolean
14
+ ) => void;
10
15
  }
11
16
 
12
17
  export function SuggestionItem({
@@ -43,7 +48,12 @@ export function SuggestionItem({
43
48
  disabled={isDisabled}
44
49
  onClick={() => {
45
50
  if (!isDisabled && onClick) {
46
- onClick(option.props.value, option.props.label, true);
51
+ onClick(
52
+ option.props.value,
53
+ option.props.label,
54
+ true,
55
+ option.props.obfuscate ?? false
56
+ );
47
57
  }
48
58
  }}
49
59
  >
@@ -25,7 +25,8 @@ export interface SuggestionListProps
25
25
  onOptionSelect?: (
26
26
  value: string,
27
27
  label: string | undefined,
28
- isSuggestion: boolean
28
+ isSuggestion: boolean,
29
+ obfuscate: boolean
29
30
  ) => void;
30
31
  noSuggestionMessage?: React.ReactNode;
31
32
  trimCustomInput?: boolean;
@@ -112,7 +113,13 @@ export function SuggestionList({
112
113
  const optionValue = option?.props.value || value;
113
114
 
114
115
  requestAnimationFrame(() => {
115
- onOptionSelect && onOptionSelect(optionValue, label, isSuggestion);
116
+ onOptionSelect &&
117
+ onOptionSelect(
118
+ optionValue,
119
+ label,
120
+ isSuggestion,
121
+ option?.props.obfuscate ?? false
122
+ );
116
123
  });
117
124
 
118
125
  break;
@@ -126,7 +133,13 @@ export function SuggestionList({
126
133
  }
127
134
 
128
135
  requestAnimationFrame(() => {
129
- onOptionSelect && onOptionSelect(optionProps.value, optionProps.label, true);
136
+ onOptionSelect &&
137
+ onOptionSelect(
138
+ optionProps.value,
139
+ optionProps.label,
140
+ true,
141
+ optionProps.obfuscate ?? false
142
+ );
130
143
  });
131
144
  break;
132
145
  }
@@ -260,6 +273,12 @@ export function SuggestionList({
260
273
  const keywords = props.keywords?.map(k => k.toLocaleLowerCase()) || [];
261
274
  const optionValue = String(props.value).toLocaleLowerCase();
262
275
  const searchValue = value.toLocaleLowerCase();
276
+ const obfuscate = props.obfuscate ?? false;
277
+
278
+ // Obfuscated options can only be searched by label or keywords, not by value
279
+ if (obfuscate) {
280
+ return label.includes(searchValue) || keywords.some(k => k.includes(searchValue));
281
+ }
263
282
 
264
283
  return (
265
284
  label.includes(searchValue) ||
@@ -1,7 +1,6 @@
1
1
  .footer {
2
2
  width: 100%;
3
3
  min-height: 0;
4
- border-top: 1px solid rgb(221, 221, 221);
5
4
  padding: var(--padding) var(--padding-large);
6
5
  gap: var(--gap);
7
6
  }
@@ -18,7 +18,7 @@ export const Footer = React.forwardRef<HTMLElement, FooterProps>(function Footer
18
18
  <HStack
19
19
  ref={ref}
20
20
  as="footer"
21
- className={clsx(styles.footer, className, 'footer', 'tcn-footer')}
21
+ className={clsx(styles.footer, className, 'tcn-footer')}
22
22
  data-hierarchy={hierarchy}
23
23
  data-size={size}
24
24
  {...props}
@@ -1,3 +1,5 @@
1
+ export * from './body/h_body.js';
2
+ export * from './body/v_body.js';
1
3
  export * from './column/column.js';
2
4
  export * from './divider/divider.js';
3
5
  export * from './footer/footer.js';
@@ -8,5 +10,4 @@ export * from './list/list.js';
8
10
  export * from './list/section_header.js';
9
11
  export * from './sidebar_end/sidebar_end.js';
10
12
  export * from './sidebar_start/sidebar_start.js';
11
- export * from './body/h_body.js';
12
- export * from './body/v_body.js';
13
+ export * from './utility_bar/utility_bar.js';