Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update the existing boolean attributes pattern #123

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

- `ReactComponent` - A React component that you want to
convert to a Web Component.
- `options` - An set of parameters.
- `options` - A set of parameters.

- `options.shadow` - Use shadow DOM rather than light DOM.
- `options.props` - Array of camelCasedProps to watch as String values or { [camelCasedProps]: "string" | "number" | "boolean" | "function" | "json" }

- When specifying Array or Object as the type, the string passed into the attribute must pass `JSON.parse()` requirements.
- When specifying Boolean as the type, "true", "1", "yes", "TRUE", and "t" are mapped to `true`. All strings NOT begining with t, T, 1, y, or Y will be `false`.
- When specifying Boolean as the type, "true", "1", "yes", "TRUE", and "t" are mapped to `true`. All strings NOT beginning with t, T, 1, y, or Y will be `false`.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@christopherjbaker any suggestions on the format of mentioning the deprecated behavior and the new behavior

- When specifying Function as the type, the string passed into the attribute must be the name of a function on `window` (or `global`). The `this` context of the function will be the instance of the WebComponent / HTMLElement when called.
- If PropTypes are defined on the React component, the `options.props` will be ignored and the PropTypes will be used instead.
However, we strongly recommend using `options.props` instead of PropTypes as it is usually not a good idea to use PropTypes in production.
Expand Down Expand Up @@ -82,7 +82,7 @@ document.body.innerHTML =
console.log(document.body.firstElementChild.innerHTML) // "<h1>Hello, Christopher</h1>"
```

If `options.props` is specified, R2WC will use those props instead of the keys from propTypes. If it's an array, all corresponding kebob-cased attr values will be passed as strings to the underlying React component.
If `options.props` is specified, R2WC will use those props instead of the keys from propTypes. If it's an array, all corresponding kebab-cased attr values will be passed as strings to the underlying React component.

```js
function Greeting({ camelCaseName }) {
Expand Down
16 changes: 12 additions & 4 deletions packages/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,12 @@ export default function r2wc<Props, Context>(
const type = propTypes[prop]
const transform = transforms[type]

if (value && transform?.parse) {
if (!value && type === "boolean") {
//@ts-ignore
this[propsSymbol][prop] = transform.parse(value, this)
this[propsSymbol][prop] = true
} else if (value && transform?.parse) {
//@ts-ignore
this[propsSymbol][prop] = transform.parse(value, attribute, this)
}
}
}
Expand Down Expand Up @@ -126,8 +129,13 @@ export default function r2wc<Props, Context>(
const transform = transforms[type]

if (prop in propTypes && transform?.parse) {
//@ts-ignore
this[propsSymbol][prop] = transform.parse(value, this)
if (!value && type === "boolean") {
//@ts-ignore
this[propsSymbol][prop] = true
} else {
//@ts-ignore
this[propsSymbol][prop] = transform.parse(value, attribute, this)
}

this[renderSymbol]()
}
Expand Down
21 changes: 20 additions & 1 deletion packages/core/src/transforms/boolean.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
import type { Transform } from "./index"

let LOG_DEPRECATION_WARNING = true
const string: Transform<boolean> = {
stringify: (value) => (value ? "true" : "false"),
parse: (value) => /^[ty1-9]/i.test(value),
parse: (value, attribute) => {
const trueRegex = new RegExp(`^\b(true|${attribute})\b$`, "gi")
const falseRegex = new RegExp(`^\bfalse\b$`, "gi")
const deprecatedRegex = new RegExp(`^[ty1-9]`, "gi")

if (trueRegex.test(value)) {
return true
} else if (falseRegex.test(value)) {
return false
} else {
if (LOG_DEPRECATION_WARNING) {
console.warn(
`[${attribute}="${value}"] The current pattern for boolean attributes has been marked as deprecated. In a future release, this pattern will no longer be supported. To avoid compatibility issues, please migrate to the new behavior and use the attribute without a value or pass 'true', '<attribute>', or an empty string for the value to represent true. Otherwise, the attribute will be considered false.`,
)
LOG_DEPRECATION_WARNING = false
}
return deprecatedRegex.test(value)
}
},
}

export default string
2 changes: 1 addition & 1 deletion packages/core/src/transforms/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Transform } from "./index"

const string: Transform<(...args: unknown[]) => unknown> = {
stringify: (value) => value.name,
parse: (value, element) => {
parse: (value, _, element) => {
const fn = (() => {
if (typeof window !== "undefined" && value in window) {
// @ts-expect-error
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/transforms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import json from "./json"

export interface Transform<Type> {
stringify?: (value: Type) => string
parse: (value: string, element: HTMLElement) => Type
parse: (value: string, attribute: string, element: HTMLElement) => Type
}

const transforms = {
Expand Down