diff --git a/docs/figma-text-shadow.md b/docs/figma-text-shadow.md new file mode 100644 index 00000000..46405b4a --- /dev/null +++ b/docs/figma-text-shadow.md @@ -0,0 +1,58 @@ +# Figma text shadow + +The text shadow is handled as the shadow of the effect from figma. + +![](https://static.figma.com/uploads/9def6cce093b164306328ee228028155d13d72d0) + +[figma DropShadowEffect](https://www.figma.com/plugin-docs/api/Effect/#dropshadoweffect) + +[W3C](https://www.w3.org/TR/css-text-decor-4/#propdef-text-shadow) + +## drop-shadow + +**css** + +- [`text-shadow`](https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow) + +**syntax** + +1. offsetX offsetY blurRadius color +2. color offsetX offsetY blurRadius +3. offsetX offsetY color +4. color offsetX offsetY + +```css +text-shadow: 1px 1px 2px #ff2; +text-shadow: 1px 1px 2px red, 0 0 1em blue, 0 0 0.2em blue; +``` + +**flutter** + +- [`Shadow`](https://api.flutter.dev/flutter/dart-ui/Shadow-class.html) + +```dart +Shadow( + offset: Offset(10.0, 10.0), + blurRadius: 3.0, + color: Color.fromARGB(255, 0, 0, 0), +) +``` + +### inner-shadow + +It is not currently supported, and it appears to be replaced with drop-shadow. + +## Why text shadow isn't support `spread radius`? + +W3 describes why there is not current spread property support for text-shadow, thous we can expect this to be supported in the future. Yet other platform such as Flutter also has no spread support + +_from w3's Text Shadows: the text-shadow property_ +> Also unlike box-shadow, the spread distance is strictly interpreted as outset distance from any point of the glyph outline, and therefore, similar to the blur radius, creates rounded, rather than sharp, corners. +> Note: The painting order of shadows defined here is the opposite of that defined in the 1998 CSS2 Recommendation. +> The text-shadow property applies to both the ::first-line and ::first-letter pseudo-elements. +> Level 4 adds a spread radius argument to text-shadow, using the same syntax and interpretation as for box-shadow, except that corners are always rounded (since the geometry of a glyph is not so simple as a box). + + +More about Shadow on text in core CG Level +- [Open question - Stackoverflow: Why TextShadow has no spread signature](https://stackoverflow.com/questions/69809872/why-doesnt-text-shadow-support-spared-radius) +- [SkiaSharp reference](https://docs.microsoft.com/en-us/dotnet/api/skiasharp.skimagefilter.createdropshadow?view=skiasharp-2.80.2) diff --git a/editor/pages/figma/inspect-raw.tsx b/editor/pages/figma/inspect-raw.tsx index 2067e29f..7acd05a1 100644 --- a/editor/pages/figma/inspect-raw.tsx +++ b/editor/pages/figma/inspect-raw.tsx @@ -15,7 +15,6 @@ export default function InspectRaw() { } const { node, reflect, raw, remote, figma } = design; // - return ( <> { + return `${px(shadow.offset.dx)} ${px(shadow.offset.dy)} ${px( + shadow.blurRadius + )} ${color(shadow.color)}`; + }); + + return res.toString(); +} diff --git a/packages/builder-web-core/widgets-native/html-text-span/index.ts b/packages/builder-web-core/widgets-native/html-text-span/index.ts index 6121ac20..88cd91ab 100644 --- a/packages/builder-web-core/widgets-native/html-text-span/index.ts +++ b/packages/builder-web-core/widgets-native/html-text-span/index.ts @@ -64,6 +64,7 @@ export class Text extends TextChildWidget { "line-height": css.length(this.textStyle.lineHeight), "text-align": this.textAlign, "text-decoration": css.textDecoration(this.textStyle.decoration), + "text-shadow": css.textShadow(this.textStyle.textShadow), // ------------------------------------------ "min-height": css.px(this.height), // TODO: do not specify width when parent is a flex container. diff --git a/packages/coli b/packages/coli index 83d3cb54..519de9d7 160000 --- a/packages/coli +++ b/packages/coli @@ -1 +1 @@ -Subproject commit 83d3cb546b753859cb23ef2a79346ac438aae563 +Subproject commit 519de9d7ebe17cd7b5d0f97d966ee5f239434edd diff --git a/packages/design-sdk b/packages/design-sdk index ee6d232d..90b588f1 160000 --- a/packages/design-sdk +++ b/packages/design-sdk @@ -1 +1 @@ -Subproject commit ee6d232d652c1c062598d73e6d69848ff2175f2d +Subproject commit 90b588f1604539d08a30fa040721bca74dac2dd8 diff --git a/packages/designto-flutter/dart-ui/dart-ui-shadow.ts b/packages/designto-flutter/dart-ui/dart-ui-shadow.ts new file mode 100644 index 00000000..69ecdb70 --- /dev/null +++ b/packages/designto-flutter/dart-ui/dart-ui-shadow.ts @@ -0,0 +1,37 @@ +import * as flutter from "@flutter-builder/flutter"; +import * as dartui from "."; +import { roundNumber } from "@reflect-ui/uiutils"; +import { TextShadowManifest } from "@reflect-ui/core"; + +/** + * README + * https://api.flutter.dev/flutter/dart-ui/Shadow-class.html + */ + +export function shadow( + shadows: ReadonlyArray +): Array { + // if no shadow filtered available, return undefined + if (shadows.length == 0) { + return undefined; + } + + const _shadows = shadows.map((d: TextShadowManifest) => { + return new flutter.Shadow({ + color: dartui.color(d.color), + blurRadius: requiredNumber(d.blurRadius), + offset: dartui.offset(d.offset), + }); + }); + + // return undefined if array is empty, since it's not needed. + return _shadows.length > 0 ? _shadows : undefined; +} + +function requiredNumber(number: number): number { + const rounded = roundNumber(number); + if (rounded == 0) { + return undefined; + } + return rounded; +} diff --git a/packages/designto-flutter/dart-ui/index.ts b/packages/designto-flutter/dart-ui/index.ts index 77c54469..5218fb7c 100644 --- a/packages/designto-flutter/dart-ui/index.ts +++ b/packages/designto-flutter/dart-ui/index.ts @@ -2,4 +2,5 @@ export * from "./dart-ui-clip"; export * from "./dart-ui-color"; export * from "./dart-ui-offset"; export * from "./dart-ui-radius"; +export * from "./dart-ui-shadow"; export * from "./dart-ui-text-align"; diff --git a/packages/designto-flutter/painting/painting-box-shadow.ts b/packages/designto-flutter/painting/painting-box-shadow.ts index 5c77dee8..d7bdbe4d 100644 --- a/packages/designto-flutter/painting/painting-box-shadow.ts +++ b/packages/designto-flutter/painting/painting-box-shadow.ts @@ -13,6 +13,10 @@ export function boxShadow( const boxShadows: Array = shadows.map( (d: BoxShadowManifest) => { + if (!d) { + return; + } + return new flutter.BoxShadow({ color: dartui.color(d.color), blurRadius: requiredNumber(d.blurRadius), diff --git a/packages/designto-flutter/painting/painting-text-style.ts b/packages/designto-flutter/painting/painting-text-style.ts index 5b5610c8..f88b9344 100644 --- a/packages/designto-flutter/painting/painting-text-style.ts +++ b/packages/designto-flutter/painting/painting-text-style.ts @@ -1,4 +1,4 @@ -import type { ITextStyle } from "@reflect-ui/core"; +import type { ITextStyle, TextShadowManifest } from "@reflect-ui/core"; import * as flutter from "@flutter-builder/flutter"; import { textDecoration } from "./painting-text-decoration"; import { fontStyle } from "./painting-font-style"; @@ -10,6 +10,7 @@ export function textStyle(style: ITextStyle): flutter.TextStyle { const { fontFamily, letterSpacing } = style; let decoration: flutter.TextDecoration = textDecoration(style.decoration); const fontWeight: flutter.FontWeight = flutter.FontWeight[style.fontWeight]; + return new flutter.TextStyle({ fontSize: rd(style.fontSize), fontWeight: fontWeight, @@ -19,5 +20,6 @@ export function textStyle(style: ITextStyle): flutter.TextStyle { letterSpacing: length.letterSpacing(style.fontSize, letterSpacing), height: length.multiple(style.fontSize, style.lineHeight), decoration: decoration, + shadows: dartui.shadow(style.textShadow), }); } diff --git a/packages/designto-token/token-text/index.ts b/packages/designto-token/token-text/index.ts index 1af0f391..5f5db2fc 100644 --- a/packages/designto-token/token-text/index.ts +++ b/packages/designto-token/token-text/index.ts @@ -1,5 +1,5 @@ import { nodes } from "@design-sdk/core"; -import { RenderedText, TextStyle } from "@reflect-ui/core"; +import { RenderedText, TextStyle, TextShadowManifest } from "@reflect-ui/core"; import { keyFromNode } from "../key"; /** @@ -47,6 +47,7 @@ export function fromText(node: nodes.ReflectTextNode): RenderedText { color: node.primaryColor, lineHeight: node.lineHeight, letterSpacing: node.letterSpacing, + textShadow: node.shadows as TextShadowManifest[], }), ...wh, }); diff --git a/packages/reflect-core b/packages/reflect-core index 01478e5a..76fad2f4 160000 --- a/packages/reflect-core +++ b/packages/reflect-core @@ -1 +1 @@ -Subproject commit 01478e5ac63b2f55d70eff735c6248b69e4c64ee +Subproject commit 76fad2f4ebb6485ab13b77e8a0a37cb7b63e36ba diff --git a/yarn.lock b/yarn.lock index dc92cf7b..d289c5ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1182,7 +1182,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.8", "@babel/runtime@^7.15.3", "@babel/runtime@^7.15.4", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.8", "@babel/runtime@^7.15.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.0.tgz#e27b977f2e2088ba24748bf99b5e1dece64e4f0b" integrity sha512-Nht8L0O8YCktmsDV6FqFue7vQLRx3Hb0B37lS5y0jDRqRxlBG4wIJHnf9/bgSE2UyipKFA01YtS+npRdTWBUyw== @@ -1230,15 +1230,6 @@ "@babel/helper-validator-identifier" "^7.15.7" to-fast-properties "^2.0.0" -"@base-sdk-fp/auth@0.1.0-2": - version "0.1.0-2" - resolved "https://registry.yarnpkg.com/@base-sdk-fp/auth/-/auth-0.1.0-2.tgz#9932e76d4aa7b88c8eed23cfdf0e949b581d16d4" - integrity sha512-1cnAftih+EOfE+h7QqiMDCNZfSiRfVTKQPDPeSyCIxlJVKuKDJPCuGJOJfRlQ165u3pU61saeC7ni6Q8ARuWOA== - dependencies: - "@base-sdk/core" "0.1.0-1" - axios-retry "^3.1.9" - otplib "^12.0.1" - "@base-sdk/base@0.1.0-5", "@base-sdk/base@^0.1.0-5": version "0.1.0-5" resolved "https://registry.yarnpkg.com/@base-sdk/base/-/base-0.1.0-5.tgz#3a08c23586e61147075d4b214ecd1f7934cf1292" @@ -1268,14 +1259,6 @@ "@reflect-ui/core" "0.0.2-rc.7" axios "^0.21.0" -"@base-sdk/core@0.1.0-1": - version "0.1.0-1" - resolved "https://registry.yarnpkg.com/@base-sdk/core/-/core-0.1.0-1.tgz#0cc7102a658caa2e783586f7fb705574711f0072" - integrity sha512-FRI5tUq4fr3TU5b077O9gGXrZgAll71wtc+mBPN644xVsntnluMvrbLoCRJd8z5Zp98avkbxkulX8QVoiYFn4g== - dependencies: - "@reflect-ui/core" "0.0.2-rc.7" - axios "^0.21.0" - "@base-sdk/hosting@0.1.0-1": version "0.1.0-1" resolved "https://registry.yarnpkg.com/@base-sdk/hosting/-/hosting-0.1.0-1.tgz#bf16050cadd1c766f0813bc7bb14344b28e9910d" @@ -2168,44 +2151,6 @@ dependencies: "@octokit/openapi-types" "^11.2.0" -"@otplib/core@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@otplib/core/-/core-12.0.1.tgz#73720a8cedce211fe5b3f683cd5a9c098eaf0f8d" - integrity sha512-4sGntwbA/AC+SbPhbsziRiD+jNDdIzsZ3JUyfZwjtKyc/wufl1pnSIaG4Uqx8ymPagujub0o92kgBnB89cuAMA== - -"@otplib/plugin-crypto@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@otplib/plugin-crypto/-/plugin-crypto-12.0.1.tgz#2b42c624227f4f9303c1c041fca399eddcbae25e" - integrity sha512-qPuhN3QrT7ZZLcLCyKOSNhuijUi9G5guMRVrxq63r9YNOxxQjPm59gVxLM+7xGnHnM6cimY57tuKsjK7y9LM1g== - dependencies: - "@otplib/core" "^12.0.1" - -"@otplib/plugin-thirty-two@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@otplib/plugin-thirty-two/-/plugin-thirty-two-12.0.1.tgz#5cc9b56e6e89f2a1fe4a2b38900ca4e11c87aa9e" - integrity sha512-MtT+uqRso909UkbrrYpJ6XFjj9D+x2Py7KjTO9JDPhL0bJUYVu5kFP4TFZW4NFAywrAtFRxOVY261u0qwb93gA== - dependencies: - "@otplib/core" "^12.0.1" - thirty-two "^1.0.2" - -"@otplib/preset-default@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@otplib/preset-default/-/preset-default-12.0.1.tgz#cb596553c08251e71b187ada4a2246ad2a3165ba" - integrity sha512-xf1v9oOJRyXfluBhMdpOkr+bsE+Irt+0D5uHtvg6x1eosfmHCsCC6ej/m7FXiWqdo0+ZUI6xSKDhJwc8yfiOPQ== - dependencies: - "@otplib/core" "^12.0.1" - "@otplib/plugin-crypto" "^12.0.1" - "@otplib/plugin-thirty-two" "^12.0.1" - -"@otplib/preset-v11@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@otplib/preset-v11/-/preset-v11-12.0.1.tgz#4c7266712e7230500b421ba89252963c838fc96d" - integrity sha512-9hSetMI7ECqbFiKICrNa4w70deTUfArtwXykPUvSHWOdzOlfa9ajglu7mNCntlvxycTiOAXkQGwjQCzzDEMRMg== - dependencies: - "@otplib/core" "^12.0.1" - "@otplib/plugin-crypto" "^12.0.1" - "@otplib/plugin-thirty-two" "^12.0.1" - "@pmmmwh/react-refresh-webpack-plugin@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz#1eec460596d200c0236bf195b078a5d1df89b766" @@ -3848,7 +3793,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.32.tgz#2ca61c9ef8c77f6fa1733be9e623ceb0d372ad96" integrity sha512-JcII3D5/OapPGx+eJ+Ik1SQGyt6WvuqdRfh9jUwL6/iHGjmyOriBDciBUu7lEIBTL2ijxwrR70WUnw5AEDmFvQ== -"@types/node@^15.12.1", "@types/node@^15.6.0": +"@types/node@^15.12.1": version "15.14.9" resolved "https://registry.yarnpkg.com/@types/node/-/node-15.14.9.tgz#bc43c990c3c9be7281868bbc7b8fdd6e2b57adfa" integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== @@ -3926,7 +3871,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^17.0.14", "@types/react@^17.0.3": +"@types/react@*", "@types/react@^17.0.3": version "17.0.34" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.34.tgz#797b66d359b692e3f19991b6b07e4b0c706c0102" integrity sha512-46FEGrMjc2+8XhHXILr+3+/sTe3OfzSPU9YGKILLrUYbQ1CLQC9Daqo1KzENGXAWwrFwiY0l4ZbF20gRvgpWTg== @@ -4776,14 +4721,6 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== -axios-retry@^3.1.9: - version "3.2.4" - resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.2.4.tgz#f447a53c3456f5bfeca18f20c3a3272207d082ae" - integrity sha512-Co3UXiv4npi6lM963mfnuH90/YFLKWWDmoBYfxkHT5xtkSSWNqK9zdG3fw5/CP/dsoKB5aMMJCsgab+tp1OxLQ== - dependencies: - "@babel/runtime" "^7.15.4" - is-retry-allowed "^2.2.0" - axios@0.21.4, axios@^0.21.0: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" @@ -9661,11 +9598,6 @@ is-retry-allowed@^1.0.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== -is-retry-allowed@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" - integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== - is-root@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" @@ -12035,15 +11967,6 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" -otplib@^12.0.1: - version "12.0.1" - resolved "https://registry.yarnpkg.com/otplib/-/otplib-12.0.1.tgz#c1d3060ab7aadf041ed2960302f27095777d1f73" - integrity sha512-xDGvUOQjop7RDgxTQ+o4pOol0/3xSZzawTiPKRrHnQWAy0WjhNs/5HdIDJCrqC4MBynmjXgULc6YfioaxZeFgg== - dependencies: - "@otplib/core" "^12.0.1" - "@otplib/preset-default" "^12.0.1" - "@otplib/preset-v11" "^12.0.1" - overlayscrollbars@^1.13.1: version "1.13.1" resolved "https://registry.yarnpkg.com/overlayscrollbars/-/overlayscrollbars-1.13.1.tgz#0b840a88737f43a946b9d87875a2f9e421d0338a" @@ -14958,11 +14881,6 @@ textextensions@^2.5.0: resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.6.0.tgz#d7e4ab13fe54e32e08873be40d51b74229b00fc4" integrity sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ== -thirty-two@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" - integrity sha1-TKL//AKlEpDSdEueP1V2k8prYno= - throat@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375"